Skip to main content

miden_base_sys/bindings/
note.rs

1extern crate alloc;
2
3use alloc::vec::Vec;
4
5use miden_stdlib_sys::{Felt, Word};
6
7use super::{AccountId, AttachmentLocation, NoteType, RawAccountId, Recipient, Tag};
8
9const MAX_NOTE_STORAGE_ITEMS: usize = 1024;
10const MAX_ATTACHMENTS_PER_NOTE: usize = 4;
11const MAX_ATTACHMENT_WORDS: usize = 256;
12
13#[allow(improper_ctypes)]
14unsafe extern "C" {
15    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
16    #[link_name = "miden::protocol::note::compute_and_store_recipient"]
17    fn extern_note_build_recipient(
18        storage_ptr: *mut Felt,
19        num_storage_items: usize,
20        serial_num_f0: Felt,
21        serial_num_f1: Felt,
22        serial_num_f2: Felt,
23        serial_num_f3: Felt,
24        script_root_f0: Felt,
25        script_root_f1: Felt,
26        script_root_f2: Felt,
27        script_root_f3: Felt,
28        ptr: *mut Recipient,
29    );
30    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
31    #[link_name = "miden::protocol::note::compute_storage_commitment"]
32    fn extern_note_compute_storage_commitment(
33        storage_ptr: *const Felt,
34        num_storage_items: usize,
35        ptr: *mut Word,
36    );
37    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
38    #[link_name = "miden::protocol::note::write_attachment_commitments_to_memory"]
39    fn extern_note_write_attachment_commitments_to_memory(
40        attachments_commitment_f0: Felt,
41        attachments_commitment_f1: Felt,
42        attachments_commitment_f2: Felt,
43        attachments_commitment_f3: Felt,
44        dest_ptr: *mut Felt,
45    ) -> usize;
46    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
47    #[link_name = "miden::protocol::note::write_attachment_to_memory"]
48    fn extern_note_write_attachment_to_memory(
49        attachment_commitment_f0: Felt,
50        attachment_commitment_f1: Felt,
51        attachment_commitment_f2: Felt,
52        attachment_commitment_f3: Felt,
53        dest_ptr: *mut Felt,
54    ) -> usize;
55    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
56    #[link_name = "miden::protocol::note::write_indexed_attachment_to_memory"]
57    fn extern_note_write_indexed_attachment_to_memory(
58        num_attachments: Felt,
59        attachment_commitments_ptr: *const Felt,
60        attachment_idx: Felt,
61        dest_ptr: *mut Felt,
62    ) -> usize;
63    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
64    #[link_name = "miden::protocol::note::compute_recipient"]
65    fn extern_note_compute_recipient(
66        serial_num_f0: Felt,
67        serial_num_f1: Felt,
68        serial_num_f2: Felt,
69        serial_num_f3: Felt,
70        script_root_f0: Felt,
71        script_root_f1: Felt,
72        script_root_f2: Felt,
73        script_root_f3: Felt,
74        storage_commitment_f0: Felt,
75        storage_commitment_f1: Felt,
76        storage_commitment_f2: Felt,
77        storage_commitment_f3: Felt,
78        ptr: *mut Recipient,
79    );
80    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
81    #[link_name = "miden::protocol::note::metadata_into_sender"]
82    fn extern_note_metadata_into_sender(
83        metadata_f0: Felt,
84        metadata_f1: Felt,
85        metadata_f2: Felt,
86        metadata_f3: Felt,
87        ptr: *mut RawAccountId,
88    );
89    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
90    #[link_name = "miden::protocol::note::metadata_into_attachment_schemes"]
91    fn extern_note_metadata_into_attachment_schemes(
92        metadata_f0: Felt,
93        metadata_f1: Felt,
94        metadata_f2: Felt,
95        metadata_f3: Felt,
96        ptr: *mut Word,
97    );
98    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
99    #[link_name = "miden::protocol::note::metadata_into_note_type"]
100    fn extern_note_metadata_into_note_type(
101        metadata_f0: Felt,
102        metadata_f1: Felt,
103        metadata_f2: Felt,
104        metadata_f3: Felt,
105    ) -> Felt;
106    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
107    #[link_name = "miden::protocol::note::metadata_into_tag"]
108    fn extern_note_metadata_into_tag(
109        metadata_f0: Felt,
110        metadata_f1: Felt,
111        metadata_f2: Felt,
112        metadata_f3: Felt,
113    ) -> Felt;
114    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
115    #[link_name = "miden::protocol::note::find_attachment_idx"]
116    fn extern_note_find_attachment_idx(
117        attachment_scheme: Felt,
118        metadata_f0: Felt,
119        metadata_f1: Felt,
120        metadata_f2: Felt,
121        metadata_f3: Felt,
122        ptr: *mut AttachmentLocation,
123    );
124}
125
126/// Computes and stores a note recipient from serial number, script root, and storage elements.
127///
128/// This maps to `miden::protocol::note::compute_and_store_recipient`, which also inserts the
129/// provided storage into the advice map under the storage commitment used by the returned
130/// recipient digest.
131///
132/// Panics if `storage` contains more than 1024 elements.
133pub fn compute_and_store_recipient(
134    serial_num: Word,
135    script_root: Word,
136    storage: Vec<Felt>,
137) -> Recipient {
138    assert!(
139        storage.len() <= MAX_NOTE_STORAGE_ITEMS,
140        "note storage cannot contain more than {MAX_NOTE_STORAGE_ITEMS} items"
141    );
142
143    let rust_ptr = if storage.is_empty() {
144        0
145    } else {
146        storage.as_ptr().addr() as u32
147    };
148    let miden_ptr = rust_ptr / 4;
149
150    // Vec storage comes from the SDK allocator, which only produces word-aligned pointers.
151    assert_eq!(miden_ptr % 4, 0, "storage pointer must be word-aligned");
152
153    unsafe {
154        let mut ret_area = ::core::mem::MaybeUninit::<Recipient>::uninit();
155        extern_note_build_recipient(
156            miden_ptr as *mut Felt,
157            storage.len(),
158            serial_num[0],
159            serial_num[1],
160            serial_num[2],
161            serial_num[3],
162            script_root[0],
163            script_root[1],
164            script_root[2],
165            script_root[3],
166            ret_area.as_mut_ptr(),
167        );
168        ret_area.assume_init()
169    }
170}
171
172/// Builds a note recipient from the provided serial number, script root, and storage elements.
173///
174/// This is retained as an SDK-friendly alias for [`compute_and_store_recipient`].
175pub fn build_recipient(serial_num: Word, script_root: Word, storage: Vec<Felt>) -> Recipient {
176    compute_and_store_recipient(serial_num, script_root, storage)
177}
178
179/// Computes the commitment to the provided note storage elements.
180///
181/// Panics if `storage` contains more than 1024 elements.
182pub fn compute_storage_commitment(storage: &[Felt]) -> Word {
183    assert!(
184        storage.len() <= MAX_NOTE_STORAGE_ITEMS,
185        "note storage cannot contain more than {MAX_NOTE_STORAGE_ITEMS} items"
186    );
187
188    let rust_ptr = if storage.is_empty() {
189        0
190    } else {
191        storage.as_ptr().addr() as u32
192    };
193    let miden_ptr = rust_ptr / 4;
194
195    assert_eq!(miden_ptr % 4, 0, "storage pointer must be word-aligned");
196
197    unsafe {
198        let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
199        extern_note_compute_storage_commitment(
200            miden_ptr as *const Felt,
201            storage.len(),
202            ret_area.as_mut_ptr(),
203        );
204        ret_area.assume_init()
205    }
206}
207
208/// Writes attachment commitments from the advice map to memory.
209///
210/// The advice map must contain the preimage committed to by `attachments_commitment`.
211pub fn write_attachment_commitments_to_memory(attachments_commitment: Word) -> Vec<Word> {
212    let mut commitments: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENTS_PER_NOTE);
213    let num_attachments = unsafe {
214        let ptr = (commitments.as_mut_ptr().addr() / 4) as u32;
215        extern_note_write_attachment_commitments_to_memory(
216            attachments_commitment[0],
217            attachments_commitment[1],
218            attachments_commitment[2],
219            attachments_commitment[3],
220            ptr as *mut Felt,
221        )
222    };
223    assert!(
224        num_attachments <= MAX_ATTACHMENTS_PER_NOTE,
225        "note cannot contain more than {MAX_ATTACHMENTS_PER_NOTE} attachments"
226    );
227    unsafe {
228        commitments.set_len(num_attachments);
229    }
230    commitments
231}
232
233/// Writes one attachment from the advice map to memory.
234///
235/// The advice map must contain the attachment elements committed to by `attachment_commitment`.
236pub fn write_attachment_to_memory(attachment_commitment: Word) -> Vec<Word> {
237    let mut attachment: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENT_WORDS);
238    let num_words = unsafe {
239        let ptr = (attachment.as_mut_ptr().addr() / 4) as u32;
240        extern_note_write_attachment_to_memory(
241            attachment_commitment[0],
242            attachment_commitment[1],
243            attachment_commitment[2],
244            attachment_commitment[3],
245            ptr as *mut Felt,
246        )
247    };
248    assert!(
249        num_words <= MAX_ATTACHMENT_WORDS,
250        "note attachment cannot contain more than {MAX_ATTACHMENT_WORDS} words"
251    );
252    unsafe {
253        attachment.set_len(num_words);
254    }
255    attachment
256}
257
258/// Writes the indexed attachment from an attachment commitment list to memory.
259///
260/// The advice map must contain the selected attachment elements.
261pub fn write_indexed_attachment_to_memory(
262    attachment_commitments: &[Word],
263    attachment_idx: Felt,
264) -> Vec<Word> {
265    assert!(
266        attachment_commitments.len() <= MAX_ATTACHMENTS_PER_NOTE,
267        "note cannot contain more than {MAX_ATTACHMENTS_PER_NOTE} attachments"
268    );
269
270    let mut attachment: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENT_WORDS);
271    let num_words = unsafe {
272        let commitments_ptr = if attachment_commitments.is_empty() {
273            0
274        } else {
275            (attachment_commitments.as_ptr().addr() / 4) as u32
276        };
277        let dest_ptr = (attachment.as_mut_ptr().addr() / 4) as u32;
278        extern_note_write_indexed_attachment_to_memory(
279            Felt::from_u32(attachment_commitments.len() as u32),
280            commitments_ptr as *const Felt,
281            attachment_idx,
282            dest_ptr as *mut Felt,
283        )
284    };
285    assert!(
286        num_words <= MAX_ATTACHMENT_WORDS,
287        "note attachment cannot contain more than {MAX_ATTACHMENT_WORDS} words"
288    );
289    unsafe {
290        attachment.set_len(num_words);
291    }
292    attachment
293}
294
295/// Computes a note recipient from serial number, script root, and storage commitment.
296pub fn compute_recipient(
297    serial_num: Word,
298    script_root: Word,
299    storage_commitment: Word,
300) -> Recipient {
301    unsafe {
302        let mut ret_area = ::core::mem::MaybeUninit::<Recipient>::uninit();
303        extern_note_compute_recipient(
304            serial_num[0],
305            serial_num[1],
306            serial_num[2],
307            serial_num[3],
308            script_root[0],
309            script_root[1],
310            script_root[2],
311            script_root[3],
312            storage_commitment[0],
313            storage_commitment[1],
314            storage_commitment[2],
315            storage_commitment[3],
316            ret_area.as_mut_ptr(),
317        );
318        ret_area.assume_init()
319    }
320}
321
322/// Extracts the sender account ID from a note metadata header word.
323pub fn metadata_into_sender(metadata: Word) -> AccountId {
324    unsafe {
325        let mut ret_area = ::core::mem::MaybeUninit::<RawAccountId>::uninit();
326        extern_note_metadata_into_sender(
327            metadata[0],
328            metadata[1],
329            metadata[2],
330            metadata[3],
331            ret_area.as_mut_ptr(),
332        );
333        ret_area.assume_init().into_account_id()
334    }
335}
336
337/// Extracts the four attachment schemes encoded in a note metadata header word.
338pub fn metadata_into_attachment_schemes(metadata: Word) -> Word {
339    unsafe {
340        let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
341        extern_note_metadata_into_attachment_schemes(
342            metadata[0],
343            metadata[1],
344            metadata[2],
345            metadata[3],
346            ret_area.as_mut_ptr(),
347        );
348        ret_area.assume_init()
349    }
350}
351
352/// Extracts the note type encoded in a note metadata header word.
353pub fn metadata_into_note_type(metadata: Word) -> NoteType {
354    unsafe {
355        NoteType::from(extern_note_metadata_into_note_type(
356            metadata[0],
357            metadata[1],
358            metadata[2],
359            metadata[3],
360        ))
361    }
362}
363
364/// Extracts the note tag encoded in a note metadata header word.
365pub fn metadata_into_tag(metadata: Word) -> Tag {
366    unsafe {
367        Tag::from(extern_note_metadata_into_tag(
368            metadata[0],
369            metadata[1],
370            metadata[2],
371            metadata[3],
372        ))
373    }
374}
375
376/// Searches a metadata header word for `attachment_scheme`.
377pub fn find_attachment_idx(attachment_scheme: Felt, metadata: Word) -> AttachmentLocation {
378    unsafe {
379        let mut ret_area = ::core::mem::MaybeUninit::<AttachmentLocation>::uninit();
380        extern_note_find_attachment_idx(
381            attachment_scheme,
382            metadata[0],
383            metadata[1],
384            metadata[2],
385            metadata[3],
386            ret_area.as_mut_ptr(),
387        );
388        ret_area.assume_init()
389    }
390}