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