miden_stdlib_sys/stdlib/crypto/
hashes.rs1#[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::poseidon2::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::poseidon2::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 bytes_to_u32_le_8(input: [u8; 32]) -> [u32; 8] {
133 core::array::from_fn(|i| {
134 let off = i * 4;
135 u32::from_le_bytes([input[off], input[off + 1], input[off + 2], input[off + 3]])
136 })
137 }
138
139 #[inline(always)]
141 fn bytes_to_u32_le_16(input: [u8; 64]) -> [u32; 16] {
142 core::array::from_fn(|i| {
143 let off = i * 4;
144 u32::from_le_bytes([input[off], input[off + 1], input[off + 2], input[off + 3]])
145 })
146 }
147
148 #[inline(always)]
150 fn bytes_to_u32_be_8(input: [u8; 32]) -> [u32; 8] {
151 core::array::from_fn(|i| {
152 let off = i * 4;
153 u32::from_be_bytes([input[off], input[off + 1], input[off + 2], input[off + 3]])
154 })
155 }
156
157 #[inline(always)]
159 fn bytes_to_u32_be_16(input: [u8; 64]) -> [u32; 16] {
160 core::array::from_fn(|i| {
161 let off = i * 4;
162 u32::from_be_bytes([input[off], input[off + 1], input[off + 2], input[off + 3]])
163 })
164 }
165
166 #[inline(always)]
167 fn decode_be_lanes_in_place(bytes: &mut [u8]) {
168 for chunk in bytes.chunks_exact_mut(4) {
169 chunk.reverse();
170 }
171 }
172
173 #[inline]
175 pub fn blake3_hash(input: [u8; 32]) -> [u8; 32] {
176 use crate::intrinsics::WordAligned;
177
178 let lanes = bytes_to_u32_le_8(input);
179 unsafe {
180 let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<[u8; 32]>>::uninit();
181 let ptr = ret_area.as_mut_ptr() as *mut u8;
182 extern_blake3_hash(
183 lanes[0], lanes[1], lanes[2], lanes[3], lanes[4], lanes[5], lanes[6], lanes[7], ptr,
184 );
185 ret_area.assume_init().into_inner()
186 }
187 }
188
189 #[inline]
191 pub fn blake3_merge(input: [u8; 64]) -> [u8; 32] {
192 let lanes = bytes_to_u32_le_16(input);
193 unsafe {
194 let mut ret_area = ::core::mem::MaybeUninit::<[u8; 32]>::uninit();
195 let ptr = ret_area.as_mut_ptr() as *mut u8;
196 extern_blake3_merge(
197 lanes[0], lanes[1], lanes[2], lanes[3], lanes[4], lanes[5], lanes[6], lanes[7],
198 lanes[8], lanes[9], lanes[10], lanes[11], lanes[12], lanes[13], lanes[14],
199 lanes[15], ptr,
200 );
201 ret_area.assume_init()
202 }
203 }
204
205 #[inline]
207 pub fn sha256_hash(input: [u8; 32]) -> [u8; 32] {
208 use crate::intrinsics::WordAligned;
209
210 let lanes = bytes_to_u32_be_8(input);
211 unsafe {
212 let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<[u8; 32]>>::uninit();
213 let ptr = ret_area.as_mut_ptr() as *mut u8;
214 extern_sha256_hash(
215 lanes[0], lanes[1], lanes[2], lanes[3], lanes[4], lanes[5], lanes[6], lanes[7], ptr,
216 );
217 let mut output = ret_area.assume_init().into_inner();
218 decode_be_lanes_in_place(&mut output);
219 output
220 }
221 }
222
223 #[inline]
225 pub fn sha256_merge(input: [u8; 64]) -> [u8; 32] {
226 let lanes = bytes_to_u32_be_16(input);
227 unsafe {
228 let mut ret_area = ::core::mem::MaybeUninit::<[u8; 32]>::uninit();
229 let ptr = ret_area.as_mut_ptr() as *mut u8;
230 extern_sha256_merge(
231 lanes[0], lanes[1], lanes[2], lanes[3], lanes[4], lanes[5], lanes[6], lanes[7],
232 lanes[8], lanes[9], lanes[10], lanes[11], lanes[12], lanes[13], lanes[14],
233 lanes[15], ptr,
234 );
235 let mut output = ret_area.assume_init();
236 decode_be_lanes_in_place(&mut output);
237 output
238 }
239 }
240
241 #[inline]
251 pub fn hash_elements(elements: Vec<Felt>) -> Digest {
252 let rust_ptr = elements.as_ptr().addr() as u32;
253 let element_count = elements.len();
254 let num_elements = element_count as u32;
255
256 unsafe {
257 let mut ret_area = core::mem::MaybeUninit::<Word>::uninit();
258 let result_ptr = ret_area.as_mut_ptr() as *mut Felt;
259 let miden_ptr = rust_ptr / 4;
260 assert_eq(Felt::new((miden_ptr % 4) as u64), felt!(0));
262
263 if element_count.is_multiple_of(4) {
264 let start_addr = miden_ptr;
265 let end_addr = start_addr + num_elements;
266 extern_hash_words(start_addr, end_addr, result_ptr);
267 } else {
268 extern_hash_elements(miden_ptr, num_elements, result_ptr);
269 }
270
271 Digest::from_word(ret_area.assume_init())
272 }
273 }
274
275 #[inline]
283 pub fn hash_words(words: &[Word]) -> Digest {
284 let rust_ptr = words.as_ptr().addr() as u32;
285
286 let miden_ptr = rust_ptr / 4;
287 assert_eq(Felt::new((miden_ptr % 4) as u64), felt!(0));
289
290 unsafe {
291 let mut ret_area = core::mem::MaybeUninit::<Word>::uninit();
292 let result_ptr = ret_area.as_mut_ptr() as *mut Felt;
293 let start_addr = miden_ptr;
294 let end_addr = start_addr + (words.len() as u32 * 4);
295 extern_hash_words(start_addr, end_addr, result_ptr);
296
297 Digest::from_word(ret_area.assume_init())
298 }
299 }
300}
301
302#[cfg(not(all(target_family = "wasm", miden)))]
303mod imp {
304 use alloc::vec::Vec;
305
306 use crate::intrinsics::{Digest, Felt, Word};
307
308 #[inline]
310 pub fn blake3_hash(_input: [u8; 32]) -> [u8; 32] {
311 unimplemented!(
312 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
313 )
314 }
315
316 #[inline]
318 pub fn blake3_merge(_input: [u8; 64]) -> [u8; 32] {
319 unimplemented!(
320 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
321 )
322 }
323
324 #[inline]
326 pub fn sha256_hash(_input: [u8; 32]) -> [u8; 32] {
327 unimplemented!(
328 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
329 )
330 }
331
332 #[inline]
334 pub fn sha256_merge(_input: [u8; 64]) -> [u8; 32] {
335 unimplemented!(
336 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
337 )
338 }
339
340 #[inline]
343 pub fn hash_elements(_elements: Vec<Felt>) -> Digest {
344 unimplemented!(
345 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
346 )
347 }
348
349 #[inline]
352 pub fn hash_words(_words: &[Word]) -> Digest {
353 unimplemented!(
354 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
355 )
356 }
357
358 #[inline]
360 pub fn extern_hash_elements(_ptr: u32, _num_elements: u32, _result_ptr: *mut Felt) {
361 unimplemented!(
362 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
363 )
364 }
365
366 #[inline]
368 pub fn extern_hash_words(_start_addr: u32, _end_addr: u32, _result_ptr: *mut Felt) {
369 unimplemented!(
370 "miden::core::crypto::hashes bindings are only available when targeting the Miden VM"
371 )
372 }
373}
374
375pub use imp::*;