Skip to main content

miden_stdlib_sys/stdlib/
mem.rs

1#![allow(dead_code)]
2
3extern crate alloc;
4use alloc::vec::Vec;
5
6#[cfg(all(target_family = "wasm", miden))]
7use crate::felt;
8use crate::intrinsics::{Felt, Word};
9
10#[cfg(all(target_family = "wasm", miden))]
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: [R0, R1, C, write_ptr', ...]
17    ///
18    /// Where R0, R1, C are the final hasher state, and `write_ptr'` points to the end of the
19    /// copied words.
20    ///
21    /// Cycles:
22    /// - Even num_words: 43 + 9 * num_words / 2
23    /// - Odd num_words: 60 + 9 * round_down(num_words / 2)
24    #[cfg_attr(all(target_family = "wasm", miden), linkage = "extern_weak")]
25    #[link_name = "miden::core::mem::pipe_words_to_memory"]
26    fn extern_pipe_words_to_memory(num_words: Felt, write_ptr: *mut Felt, out_ptr: *mut Felt);
27
28    /// Moves an even number of words from the advice stack to memory.
29    ///
30    /// Input: [R0, R1, C, write_ptr, end_ptr, ...]
31    /// Output: [R0', R1', C', write_ptr, ...]
32    ///
33    /// Where:
34    /// - The words R0, R1, and C are the hasher state (R0 on top)
35    /// - C is the capacity
36    /// - R0, R1 are the rate portion of the state
37    /// - The value num_words = end_ptr - write_ptr must be positive and even
38    ///
39    /// Cycles: 9 + 6 * (num_words / 2)
40    #[cfg_attr(all(target_family = "wasm", miden), linkage = "extern_weak")]
41    #[link_name = "miden::core::mem::pipe_double_words_to_memory"]
42    fn extern_pipe_double_words_to_memory(
43        r00: Felt,
44        r01: Felt,
45        r02: Felt,
46        r03: Felt,
47        r10: Felt,
48        r11: Felt,
49        r12: Felt,
50        r13: Felt,
51        c0: Felt,
52        c1: Felt,
53        c2: Felt,
54        c3: Felt,
55        write_ptr: *mut Felt,
56        end_ptr: *mut Felt,
57        out_ptr: *mut Felt,
58    );
59
60    /// Moves an arbitrary number of words from the advice stack to memory and asserts it matches the commitment.
61    ///
62    /// Input: [num_words, write_ptr, COM, ...]
63    /// Output: [write_ptr', ...]
64    ///
65    /// Cycles:
66    /// - Even num_words: 58 + 9 * (num_words / 2)
67    /// - Odd num_words: 75 + 9 * round_down(num_words / 2)
68    #[cfg_attr(all(target_family = "wasm", miden), linkage = "extern_weak")]
69    #[link_name = "miden::core::mem::pipe_preimage_to_memory"]
70    pub(crate) fn extern_pipe_preimage_to_memory(
71        num_words: Felt,
72        write_ptr: *mut Felt,
73        com0: Felt,
74        com1: Felt,
75        com2: Felt,
76        com3: Felt,
77    ) -> i32;
78}
79
80/// Reads an arbitrary number of words `num_words` from the advice stack and returns them along with
81/// the digest of all read words.
82///
83/// Cycles:
84/// - Even num_words: 43 + 9 * num_words / 2
85/// - Odd num_words: 60 + 9 * round_down(num_words / 2)
86#[cfg(all(target_family = "wasm", miden))]
87pub fn pipe_words_to_memory(num_words: Felt) -> (Word, Vec<Felt>) {
88    use crate::intrinsics::WordAligned;
89
90    #[repr(C)]
91    struct Result {
92        r0: Word,
93        r1: Word,
94        c: Word,
95        write_ptr: *mut Felt,
96    }
97
98    unsafe {
99        let num_words_usize =
100            usize::try_from(num_words.as_canonical_u64()).expect("num_words must fit in usize");
101        let num_felts = num_words_usize.checked_mul(4).expect("num_words too large");
102
103        let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<Result>>::uninit();
104        let mut buf: Vec<Felt> = Vec::with_capacity(num_felts);
105
106        let rust_write_ptr = buf.as_mut_ptr().addr();
107        let rust_write_ptr_u32 = u32::try_from(rust_write_ptr).expect("write_ptr must fit in u32");
108        assert_eq!(rust_write_ptr_u32 % 4, 0, "write_ptr must be word-aligned");
109        let miden_write_ptr = rust_write_ptr_u32 / 4;
110
111        extern_pipe_words_to_memory(
112            num_words,
113            miden_write_ptr as usize as *mut Felt,
114            ret_area.as_mut_ptr() as *mut Felt,
115        );
116        buf.set_len(num_felts);
117        let Result { r0, .. } = ret_area.assume_init().into_inner();
118        (r0, buf)
119    }
120}
121
122/// Reads an arbitrary number of words `num_words` from the advice stack and returns them along with
123/// sequantial RPO hash of all read words.
124#[cfg(not(all(target_family = "wasm", miden)))]
125pub fn pipe_words_to_memory(_num_words: Felt) -> (Word, Vec<Felt>) {
126    unimplemented!("miden::core::mem bindings are only available when targeting the Miden VM")
127}
128
129/// Returns an even number of words from the advice stack along with the RPO hash of all read words.
130///
131/// Cycles: 9 + 6 * (num_words / 2)
132#[cfg(all(target_family = "wasm", miden))]
133pub fn pipe_double_words_to_memory(num_words: Felt) -> (Word, Vec<Felt>) {
134    use crate::intrinsics::WordAligned;
135
136    #[repr(C)]
137    struct Result {
138        r0: Word,
139        r1: Word,
140        c: Word,
141        write_ptr: *mut Felt,
142    }
143
144    let num_words_usize =
145        usize::try_from(num_words.as_canonical_u64()).expect("num_words must fit in usize");
146    let num_felts = num_words_usize.checked_mul(4).expect("num_words too large");
147
148    let mut buf: Vec<Felt> = Vec::with_capacity(num_felts);
149
150    let rust_write_ptr = buf.as_mut_ptr().addr();
151    let rust_write_ptr_u32 = u32::try_from(rust_write_ptr).expect("write_ptr must fit in u32");
152    assert_eq!(rust_write_ptr_u32 % 4, 0, "write_ptr must be word-aligned");
153    let miden_write_ptr = rust_write_ptr_u32 / 4;
154    let num_felts_u32 = u32::try_from(num_felts).expect("num_felts must fit in u32");
155    let miden_end_ptr = miden_write_ptr + num_felts_u32;
156
157    // Place for returned R0, R1, C, write_ptr
158    let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<Result>>::uninit();
159    let zero = felt!(0);
160    unsafe {
161        extern_pipe_double_words_to_memory(
162            zero,
163            zero,
164            zero,
165            zero, // R0
166            zero,
167            zero,
168            zero,
169            zero, // R1
170            zero,
171            zero,
172            zero,
173            zero, // C
174            miden_write_ptr as usize as *mut Felt,
175            miden_end_ptr as usize as *mut Felt,
176            ret_area.as_mut_ptr() as *mut Felt,
177        );
178        buf.set_len(num_felts);
179        let Result { r0, .. } = ret_area.assume_init().into_inner();
180        (r0, buf)
181    }
182}
183
184/// Returns an even number of words from the advice stack along with the RPO hash of all read words.
185#[cfg(not(all(target_family = "wasm", miden)))]
186pub fn pipe_double_words_to_memory(_num_words: Felt) -> (Word, Vec<Felt>) {
187    unimplemented!("miden::core::mem bindings are only available when targeting the Miden VM")
188}
189
190/// Pops an arbitrary number of words from the advice stack and asserts it matches the commitment.
191/// Returns a Vec containing the loaded words.
192#[inline]
193#[cfg(all(target_family = "wasm", miden))]
194pub fn adv_load_preimage(num_words: Felt, commitment: Word) -> Vec<Felt> {
195    // Allocate a Vec with the specified capacity
196    let num_words_usize = num_words.as_canonical_u64() as usize;
197    let num_felts = num_words_usize * 4;
198    let mut result: Vec<Felt> = Vec::with_capacity(num_felts);
199
200    let result_miden_ptr = (result.as_mut_ptr() as usize) / 4;
201    unsafe {
202        // Call pipe_preimage_to_memory to load words from advice stack
203        extern_pipe_preimage_to_memory(
204            num_words,
205            result_miden_ptr as *mut Felt,
206            commitment[0],
207            commitment[1],
208            commitment[2],
209            commitment[3],
210        );
211
212        // Set the length of the Vec to match what was loaded
213        result.set_len(num_felts);
214    }
215
216    result
217}
218
219/// Pops an arbitrary number of words from the advice stack and asserts it matches the commitment.
220/// Returns a Vec containing the loaded words.
221#[cfg(not(all(target_family = "wasm", miden)))]
222#[inline]
223pub fn adv_load_preimage(_num_words: Felt, _commitment: Word) -> Vec<Felt> {
224    unimplemented!("miden::core::mem bindings are only available when targeting the Miden VM")
225}