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: [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 = "miden::core::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 = "miden::core::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 = "miden::core::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)
82#[cfg(all(target_family = "wasm", miden))]
83pub fn pipe_words_to_memory(num_words: Felt) -> (Word, Vec<Felt>) {
84    struct Result {
85        hash: Word,
86        write_ptr: *mut Felt,
87    }
88
89    unsafe {
90        // Place for returned HASH, write_ptr
91        let mut ret_area = ::core::mem::MaybeUninit::<Result>::uninit();
92        let mut buf: Vec<Felt> = Vec::with_capacity((num_words.as_u64() * 4) as usize);
93        extern_pipe_words_to_memory(
94            num_words,
95            buf.as_mut_ptr(),
96            ret_area.as_mut_ptr() as *mut Felt,
97        );
98        let Result { hash, .. } = ret_area.assume_init();
99        (hash, buf)
100    }
101}
102
103/// Reads an arbitrary number of words `num_words` from the advice stack and returns them along with
104/// sequantial RPO hash of all read words.
105#[cfg(not(all(target_family = "wasm", miden)))]
106pub fn pipe_words_to_memory(_num_words: Felt) -> (Word, Vec<Felt>) {
107    unimplemented!("miden::core::mem bindings are only available when targeting the Miden VM")
108}
109
110/// Returns an even number of words from the advice stack along with the RPO hash of all read words.
111///
112/// Cycles: 10 + 9 * num_words / 2
113#[cfg(all(target_family = "wasm", miden))]
114pub fn pipe_double_words_to_memory(num_words: Felt) -> (Word, Vec<Felt>) {
115    struct Result {
116        c: Word,
117        b: Word,
118        a: Word,
119        write_ptr: *mut Felt,
120    }
121
122    let num_words_in_felts = num_words.as_u64() as usize * 4;
123    let mut buf: Vec<Felt> = Vec::with_capacity(num_words_in_felts);
124    let write_ptr = buf.as_mut_ptr();
125    let end_ptr = unsafe { write_ptr.add(num_words_in_felts) };
126    // Place for returned C, B, A, write_ptr
127    let mut ret_area = ::core::mem::MaybeUninit::<Result>::uninit();
128    let zero = felt!(0);
129    unsafe {
130        extern_pipe_double_words_to_memory(
131            zero,
132            zero,
133            zero,
134            zero,
135            zero,
136            zero,
137            zero,
138            zero,
139            zero,
140            zero,
141            zero,
142            zero,
143            write_ptr,
144            end_ptr,
145            ret_area.as_mut_ptr() as *mut Felt,
146        );
147        let Result { b, .. } = ret_area.assume_init();
148        // B (second) is the hash (see https://github.com/0xMiden/miden-vm/blob/3a957f7c90176914bda2139f74bff9e5700d59ac/stdlib/asm/crypto/hashes/native.masm#L1-L16 )
149        (b, buf)
150    }
151}
152
153/// Returns an even number of words from the advice stack along with the RPO hash of all read words.
154#[cfg(not(all(target_family = "wasm", miden)))]
155pub fn pipe_double_words_to_memory(_num_words: Felt) -> (Word, Vec<Felt>) {
156    unimplemented!("miden::core::mem bindings are only available when targeting the Miden VM")
157}
158
159/// Pops an arbitrary number of words from the advice stack and asserts it matches the commitment.
160/// Returns a Vec containing the loaded words.
161#[inline]
162#[cfg(all(target_family = "wasm", miden))]
163pub fn adv_load_preimage(num_words: Felt, commitment: Word) -> Vec<Felt> {
164    // Allocate a Vec with the specified capacity
165    let num_words_usize = num_words.as_u64() as usize;
166    let num_felts = num_words_usize * 4;
167    let mut result: Vec<Felt> = Vec::with_capacity(num_felts);
168
169    let result_miden_ptr = (result.as_mut_ptr() as usize) / 4;
170    unsafe {
171        // Call pipe_preimage_to_memory to load words from advice stack
172        extern_pipe_preimage_to_memory(
173            num_words,
174            result_miden_ptr as *mut Felt,
175            commitment[3],
176            commitment[2],
177            commitment[1],
178            commitment[0],
179        );
180
181        // Set the length of the Vec to match what was loaded
182        result.set_len(num_felts);
183    }
184
185    result
186}
187
188/// Pops an arbitrary number of words from the advice stack and asserts it matches the commitment.
189/// Returns a Vec containing the loaded words.
190#[cfg(not(all(target_family = "wasm", miden)))]
191#[inline]
192pub fn adv_load_preimage(_num_words: Felt, _commitment: Word) -> Vec<Felt> {
193    unimplemented!("miden::core::mem bindings are only available when targeting the Miden VM")
194}