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}