miden_stdlib_sys/stdlib/mem.rs
1#![allow(dead_code)]
2
3extern crate alloc;
4use alloc::vec::Vec;
5
6use crate::{
7 felt,
8 intrinsics::{Felt, Word},
9};
10
11unsafe extern "C" {
12
13 /// Moves an arbitrary number of words from the advice stack to memory.
14 ///
15 /// Input: [num_words, write_ptr, ...]
16 /// Output: [HASH, write_ptr', ...]
17 ///
18 /// Where HASH is the sequential RPO hash of all copied words.
19 ///
20 /// Cycles:
21 /// - Even num_words: 48 + 9 * num_words / 2
22 /// - Odd num_words: 65 + 9 * round_down(num_words / 2)
23 #[link_name = "std::mem::pipe_words_to_memory"]
24 fn extern_pipe_words_to_memory(num_words: Felt, ptr: *mut Felt, out_ptr: *mut Felt);
25
26 /// Moves an even number of words from the advice stack to memory.
27 ///
28 /// Input: [C, B, A, write_ptr, end_ptr, ...]
29 /// Output: [C, B, A, write_ptr, ...]
30 ///
31 /// Where:
32 /// - The words C, B, and A are the RPO hasher state
33 /// - A is the capacity
34 /// - C, B are the rate portion of the state
35 /// - The value num_words = end_ptr - write_ptr must be positive and even
36 ///
37 /// Cycles: 10 + 9 * num_words / 2
38 #[link_name = "std::mem::pipe_double_words_to_memory"]
39 fn extern_pipe_double_words_to_memory(
40 c0: Felt,
41 c1: Felt,
42 c2: Felt,
43 c3: Felt,
44 b0: Felt,
45 b1: Felt,
46 b2: Felt,
47 b3: Felt,
48 a0: Felt,
49 a1: Felt,
50 a2: Felt,
51 a3: Felt,
52 write_ptr: *mut Felt,
53 end_ptr: *mut Felt,
54 out_ptr: *mut Felt,
55 );
56
57 /// Moves an arbitrary number of words from the advice stack to memory and asserts it matches the commitment.
58 ///
59 /// Input: [num_words, write_ptr, COM, ...]
60 /// Output: [write_ptr', ...]
61 ///
62 /// Cycles:
63 /// - Even num_words: 58 + 9 * (num_words / 2)
64 /// - Odd num_words: 75 + 9 * round_down(num_words / 2)
65 #[link_name = "std::mem::pipe_preimage_to_memory"]
66 pub(crate) fn extern_pipe_preimage_to_memory(
67 num_words: Felt,
68 write_ptr: *mut Felt,
69 com0: Felt,
70 com1: Felt,
71 com2: Felt,
72 com3: Felt,
73 ) -> i32;
74}
75
76/// Reads an arbitrary number of words `num_words` from the advice stack and returns them along with
77/// sequantial RPO hash of all read words.
78///
79/// Cycles:
80/// - Even num_words: 48 + 9 * num_words / 2
81/// - Odd num_words: 65 + 9 * round_down(num_words / 2)
82pub fn pipe_words_to_memory(num_words: Felt) -> (Word, Vec<Felt>) {
83 struct Result {
84 hash: Word,
85 write_ptr: *mut Felt,
86 }
87
88 unsafe {
89 // Place for returned HASH, write_ptr
90 let mut ret_area = ::core::mem::MaybeUninit::<Result>::uninit();
91 let mut buf: Vec<Felt> = Vec::with_capacity((num_words.as_u64() * 4) as usize);
92 extern_pipe_words_to_memory(
93 num_words,
94 buf.as_mut_ptr(),
95 ret_area.as_mut_ptr() as *mut Felt,
96 );
97 let Result { hash, .. } = ret_area.assume_init();
98 (hash, buf)
99 }
100}
101
102/// Returns an even number of words from the advice stack along with the RPO hash of all read words.
103///
104/// Cycles: 10 + 9 * num_words / 2
105pub fn pipe_double_words_to_memory(num_words: Felt) -> (Word, Vec<Felt>) {
106 struct Result {
107 c: Word,
108 b: Word,
109 a: Word,
110 write_ptr: *mut Felt,
111 }
112
113 let num_words_in_felts = num_words.as_u64() as usize * 4;
114 let mut buf: Vec<Felt> = Vec::with_capacity(num_words_in_felts);
115 let write_ptr = buf.as_mut_ptr();
116 let end_ptr = unsafe { write_ptr.add(num_words_in_felts) };
117 // Place for returned C, B, A, write_ptr
118 let mut ret_area = ::core::mem::MaybeUninit::<Result>::uninit();
119 let zero = felt!(0);
120 unsafe {
121 extern_pipe_double_words_to_memory(
122 zero,
123 zero,
124 zero,
125 zero,
126 zero,
127 zero,
128 zero,
129 zero,
130 zero,
131 zero,
132 zero,
133 zero,
134 write_ptr,
135 end_ptr,
136 ret_area.as_mut_ptr() as *mut Felt,
137 );
138 let Result { b, .. } = ret_area.assume_init();
139 // B (second) is the hash (see https://github.com/0xMiden/miden-vm/blob/3a957f7c90176914bda2139f74bff9e5700d59ac/stdlib/asm/crypto/hashes/native.masm#L1-L16 )
140 (b, buf)
141 }
142}
143
144/// Pops an arbitrary number of words from the advice stack and asserts it matches the commitment.
145/// Returns a Vec containing the loaded words.
146#[inline]
147pub fn adv_load_preimage(num_words: Felt, commitment: Word) -> Vec<Felt> {
148 // Allocate a Vec with the specified capacity
149 let num_words_usize = num_words.as_u64() as usize;
150 let num_felts = num_words_usize * 4;
151 let mut result: Vec<Felt> = Vec::with_capacity(num_felts);
152
153 let result_miden_ptr = (result.as_mut_ptr() as usize) / 4;
154 unsafe {
155 // Call pipe_preimage_to_memory to load words from advice stack
156 extern_pipe_preimage_to_memory(
157 num_words,
158 result_miden_ptr as *mut Felt,
159 commitment[3],
160 commitment[2],
161 commitment[1],
162 commitment[0],
163 );
164
165 // Set the length of the Vec to match what was loaded
166 result.set_len(num_felts);
167 }
168
169 result
170}