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    #[repr(C)]
89    struct Result {
90        r0: Word,
91        r1: Word,
92        c: Word,
93        write_ptr: *mut Felt,
94    }
95
96    unsafe {
97        let num_words_usize =
98            usize::try_from(num_words.as_canonical_u64()).expect("num_words must fit in usize");
99        let num_felts = num_words_usize.checked_mul(4).expect("num_words too large");
100
101        let mut ret_area = ::core::mem::MaybeUninit::<Result>::uninit();
102        let mut buf: Vec<Felt> = Vec::with_capacity(num_felts);
103
104        let rust_write_ptr = buf.as_mut_ptr().addr();
105        let rust_write_ptr_u32 = u32::try_from(rust_write_ptr).expect("write_ptr must fit in u32");
106        assert_eq!(rust_write_ptr_u32 % 4, 0, "write_ptr must be word-aligned");
107        let miden_write_ptr = rust_write_ptr_u32 / 4;
108
109        extern_pipe_words_to_memory(
110            num_words,
111            miden_write_ptr as usize as *mut Felt,
112            ret_area.as_mut_ptr() as *mut Felt,
113        );
114        buf.set_len(num_felts);
115        let Result { r0, .. } = ret_area.assume_init();
116        (r0, buf)
117    }
118}
119
120/// Reads an arbitrary number of words `num_words` from the advice stack and returns them along with
121/// sequantial RPO hash of all read words.
122#[cfg(not(all(target_family = "wasm", miden)))]
123pub fn pipe_words_to_memory(_num_words: Felt) -> (Word, Vec<Felt>) {
124    unimplemented!("miden::core::mem bindings are only available when targeting the Miden VM")
125}
126
127/// Returns an even number of words from the advice stack along with the RPO hash of all read words.
128///
129/// Cycles: 9 + 6 * (num_words / 2)
130#[cfg(all(target_family = "wasm", miden))]
131pub fn pipe_double_words_to_memory(num_words: Felt) -> (Word, Vec<Felt>) {
132    #[repr(C)]
133    struct Result {
134        r0: Word,
135        r1: Word,
136        c: Word,
137        write_ptr: *mut Felt,
138    }
139
140    let num_words_usize =
141        usize::try_from(num_words.as_canonical_u64()).expect("num_words must fit in usize");
142    let num_felts = num_words_usize.checked_mul(4).expect("num_words too large");
143
144    let mut buf: Vec<Felt> = Vec::with_capacity(num_felts);
145
146    let rust_write_ptr = buf.as_mut_ptr().addr();
147    let rust_write_ptr_u32 = u32::try_from(rust_write_ptr).expect("write_ptr must fit in u32");
148    assert_eq!(rust_write_ptr_u32 % 4, 0, "write_ptr must be word-aligned");
149    let miden_write_ptr = rust_write_ptr_u32 / 4;
150    let num_felts_u32 = u32::try_from(num_felts).expect("num_felts must fit in u32");
151    let miden_end_ptr = miden_write_ptr + num_felts_u32;
152
153    // Place for returned R0, R1, C, write_ptr
154    let mut ret_area = ::core::mem::MaybeUninit::<Result>::uninit();
155    let zero = felt!(0);
156    unsafe {
157        extern_pipe_double_words_to_memory(
158            zero,
159            zero,
160            zero,
161            zero, // R0
162            zero,
163            zero,
164            zero,
165            zero, // R1
166            zero,
167            zero,
168            zero,
169            zero, // C
170            miden_write_ptr as usize as *mut Felt,
171            miden_end_ptr as usize as *mut Felt,
172            ret_area.as_mut_ptr() as *mut Felt,
173        );
174        buf.set_len(num_felts);
175        let Result { r0, .. } = ret_area.assume_init();
176        (r0, buf)
177    }
178}
179
180/// Returns an even number of words from the advice stack along with the RPO hash of all read words.
181#[cfg(not(all(target_family = "wasm", miden)))]
182pub fn pipe_double_words_to_memory(_num_words: Felt) -> (Word, Vec<Felt>) {
183    unimplemented!("miden::core::mem bindings are only available when targeting the Miden VM")
184}
185
186/// Pops an arbitrary number of words from the advice stack and asserts it matches the commitment.
187/// Returns a Vec containing the loaded words.
188#[inline]
189#[cfg(all(target_family = "wasm", miden))]
190pub fn adv_load_preimage(num_words: Felt, commitment: Word) -> Vec<Felt> {
191    // Allocate a Vec with the specified capacity
192    let num_words_usize = num_words.as_canonical_u64() as usize;
193    let num_felts = num_words_usize * 4;
194    let mut result: Vec<Felt> = Vec::with_capacity(num_felts);
195
196    let result_miden_ptr = (result.as_mut_ptr() as usize) / 4;
197    unsafe {
198        // Call pipe_preimage_to_memory to load words from advice stack
199        extern_pipe_preimage_to_memory(
200            num_words,
201            result_miden_ptr as *mut Felt,
202            commitment[0],
203            commitment[1],
204            commitment[2],
205            commitment[3],
206        );
207
208        // Set the length of the Vec to match what was loaded
209        result.set_len(num_felts);
210    }
211
212    result
213}
214
215/// Pops an arbitrary number of words from the advice stack and asserts it matches the commitment.
216/// Returns a Vec containing the loaded words.
217#[cfg(not(all(target_family = "wasm", miden)))]
218#[inline]
219pub fn adv_load_preimage(_num_words: Felt, _commitment: Word) -> Vec<Felt> {
220    unimplemented!("miden::core::mem bindings are only available when targeting the Miden VM")
221}