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}