Skip to main content

miden_base_sys/bindings/
output_note.rs

1extern crate alloc;
2use alloc::vec::Vec;
3
4use miden_stdlib_sys::{Felt, Word};
5
6use super::types::{Asset, AttachmentLocation, NoteIdx, NoteMetadata, NoteType, Recipient, Tag};
7
8const MAX_ATTACHMENTS_PER_NOTE: usize = 4;
9const MAX_ATTACHMENT_WORDS: usize = 256;
10
11#[allow(improper_ctypes)]
12unsafe extern "C" {
13    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
14    #[link_name = "miden::protocol::output_note::create"]
15    pub fn extern_output_note_create(
16        tag: Tag,
17        note_type: NoteType,
18        recipient_f0: Felt,
19        recipient_f1: Felt,
20        recipient_f2: Felt,
21        recipient_f3: Felt,
22    ) -> NoteIdx;
23    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
24    #[link_name = "miden::protocol::output_note::add_asset"]
25    pub fn extern_output_note_add_asset(
26        asset_key_f0: Felt,
27        asset_key_f1: Felt,
28        asset_key_f2: Felt,
29        asset_key_f3: Felt,
30        asset_value_f0: Felt,
31        asset_value_f1: Felt,
32        asset_value_f2: Felt,
33        asset_value_f3: Felt,
34        note_idx: NoteIdx,
35    );
36    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
37    #[link_name = "miden::protocol::output_note::get_assets_info"]
38    pub fn extern_output_note_get_assets_info(note_index: Felt, ptr: *mut (Word, Felt));
39    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
40    #[link_name = "miden::protocol::output_note::get_assets"]
41    pub fn extern_output_note_get_assets(dest_ptr: *mut Felt, note_index: Felt) -> usize;
42    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
43    #[link_name = "miden::protocol::output_note::get_attachments_commitment"]
44    pub fn extern_output_note_get_attachments_commitment(note_index: Felt, ptr: *mut Word);
45    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
46    #[link_name = "miden::protocol::output_note::get_recipient"]
47    pub fn extern_output_note_get_recipient(note_index: Felt, ptr: *mut Recipient);
48    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
49    #[link_name = "miden::protocol::output_note::get_metadata"]
50    pub fn extern_output_note_get_metadata(note_index: Felt, ptr: *mut NoteMetadata);
51    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
52    #[link_name = "miden::protocol::output_note::add_word_attachment"]
53    pub fn extern_output_note_add_word_attachment(
54        attachment_scheme: Felt,
55        attachment_f0: Felt,
56        attachment_f1: Felt,
57        attachment_f2: Felt,
58        attachment_f3: Felt,
59        note_idx: NoteIdx,
60    );
61    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
62    #[link_name = "miden::protocol::output_note::add_attachment"]
63    pub fn extern_output_note_add_attachment(
64        attachment_scheme: Felt,
65        attachment_f0: Felt,
66        attachment_f1: Felt,
67        attachment_f2: Felt,
68        attachment_f3: Felt,
69        note_idx: NoteIdx,
70    );
71    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
72    #[link_name = "miden::protocol::output_note::add_attachment_from_memory"]
73    pub fn extern_output_note_add_attachment_from_memory(
74        attachment_scheme: Felt,
75        num_words: usize,
76        attachment_ptr: *const Felt,
77        note_idx: NoteIdx,
78    );
79    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
80    #[link_name = "miden::protocol::output_note::find_attachment"]
81    pub fn extern_output_note_find_attachment(
82        attachment_scheme: Felt,
83        note_index: Felt,
84        ptr: *mut AttachmentLocation,
85    );
86    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
87    #[link_name = "miden::protocol::output_note::write_attachment_commitments_to_memory"]
88    pub fn extern_output_note_write_attachment_commitments_to_memory(
89        dest_ptr: *mut Felt,
90        note_index: Felt,
91    ) -> usize;
92    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
93    #[link_name = "miden::protocol::output_note::write_attachment_to_memory"]
94    pub fn extern_output_note_write_attachment_to_memory(
95        dest_ptr: *mut Felt,
96        attachment_idx: Felt,
97        note_index: Felt,
98    ) -> usize;
99}
100
101/// Creates a new output note and returns its index.
102///
103/// # Examples
104///
105/// Create a note and add a single asset to it:
106///
107/// ```rust,ignore
108/// // before using `Vec`/`vec!`.
109/// extern crate alloc;
110///
111/// use miden::{felt, note, output_note, Asset, NoteType, Tag, Word};
112///
113/// // Values used to derive the note recipient.
114/// let serial_num = Word::from_u64_unchecked(1, 2, 3, 4);
115/// let note_script_root = Word::from_u64_unchecked(0, 0, 0, 0);
116///
117/// let storage = alloc::vec![felt!(0); 2];
118/// let recipient = note::build_recipient(serial_num, note_script_root, storage);
119///
120/// let tag = Tag::from(felt!(0));
121/// let note_type = NoteType::from(felt!(1)); // public note type (0b01)
122///
123/// let note_idx = output_note::create(tag, note_type, recipient);
124/// output_note::add_asset(
125///     Asset::new(
126///         [felt!(0), felt!(0), felt!(0), felt!(1)],
127///         [felt!(1), felt!(0), felt!(0), felt!(0)],
128///     ),
129///     note_idx,
130/// );
131/// ```
132pub fn create(tag: Tag, note_type: NoteType, recipient: Recipient) -> NoteIdx {
133    unsafe {
134        extern_output_note_create(
135            tag,
136            note_type,
137            recipient.inner[0],
138            recipient.inner[1],
139            recipient.inner[2],
140            recipient.inner[3],
141        )
142    }
143}
144
145/// Adds a single-word attachment to the output note specified by `note_idx`.
146pub fn add_word_attachment(note_idx: NoteIdx, attachment_scheme: Felt, attachment: Word) {
147    unsafe {
148        extern_output_note_add_word_attachment(
149            attachment_scheme,
150            attachment[0],
151            attachment[1],
152            attachment[2],
153            attachment[3],
154            note_idx,
155        );
156    }
157}
158
159/// Sets the attachment of the output note specified by `note_idx` to the provided word.
160pub fn set_word_attachment(note_idx: NoteIdx, attachment_scheme: Felt, attachment: Word) {
161    add_word_attachment(note_idx, attachment_scheme, attachment);
162}
163
164/// Adds an attachment commitment to the output note specified by `note_idx`.
165///
166/// The advice map must contain an entry for the attachment elements committed to by `attachment`.
167pub fn add_attachment(note_idx: NoteIdx, attachment_scheme: Felt, attachment: Word) {
168    unsafe {
169        extern_output_note_add_attachment(
170            attachment_scheme,
171            attachment[0],
172            attachment[1],
173            attachment[2],
174            attachment[3],
175            note_idx,
176        );
177    }
178}
179
180/// Sets the attachment of the output note specified by `note_idx` to the provided commitment.
181///
182/// The advice map must contain an entry for the attachment elements committed to by `attachment`.
183pub fn set_array_attachment(note_idx: NoteIdx, attachment_scheme: Felt, attachment: Word) {
184    add_attachment(note_idx, attachment_scheme, attachment);
185}
186
187/// Adds a multi-word attachment from linear memory to the output note specified by `note_idx`.
188pub fn add_attachment_from_memory(note_idx: NoteIdx, attachment_scheme: Felt, attachment: &[Word]) {
189    let ptr = if attachment.is_empty() {
190        0
191    } else {
192        (attachment.as_ptr().addr() / 4) as u32
193    };
194
195    unsafe {
196        extern_output_note_add_attachment_from_memory(
197            attachment_scheme,
198            attachment.len(),
199            ptr as *const Felt,
200            note_idx,
201        );
202    }
203}
204
205/// Adds the asset to the output note specified by `note_idx`.
206///
207/// # Examples
208///
209/// ```rust,ignore
210/// use miden::{felt, output_note, Asset, NoteIdx};
211///
212/// // `note_idx` is returned by `output_note::create(...)`.
213/// let note_idx: NoteIdx = /* ... */
214///
215/// let asset = Asset::new(
216///     [felt!(0), felt!(0), felt!(0), felt!(1)],
217///     [felt!(1), felt!(0), felt!(0), felt!(0)],
218/// );
219/// output_note::add_asset(asset, note_idx);
220/// ```
221pub fn add_asset(asset: Asset, note_idx: NoteIdx) {
222    unsafe {
223        extern_output_note_add_asset(
224            asset.key[0],
225            asset.key[1],
226            asset.key[2],
227            asset.key[3],
228            asset.value[0],
229            asset.value[1],
230            asset.value[2],
231            asset.value[3],
232            note_idx,
233        );
234    }
235}
236
237/// Contains summary information about the assets of an output note.
238pub struct OutputNoteAssetsInfo {
239    pub commitment: Word,
240    pub num_assets: Felt,
241}
242
243/// Retrieves the assets commitment and asset count for the output note at `note_index`.
244pub fn get_assets_info(note_index: NoteIdx) -> OutputNoteAssetsInfo {
245    unsafe {
246        let mut ret_area = ::core::mem::MaybeUninit::<(Word, Felt)>::uninit();
247        extern_output_note_get_assets_info(note_index.inner, ret_area.as_mut_ptr());
248        let (commitment, num_assets) = ret_area.assume_init();
249        OutputNoteAssetsInfo {
250            commitment,
251            num_assets,
252        }
253    }
254}
255
256/// Returns the assets contained in the output note at `note_index`.
257pub fn get_assets(note_index: NoteIdx) -> Vec<Asset> {
258    const MAX_ASSETS: usize = 256;
259    let mut assets: Vec<Asset> = Vec::with_capacity(MAX_ASSETS);
260    let num_assets = unsafe {
261        let ptr = (assets.as_mut_ptr() as usize) / 4;
262        extern_output_note_get_assets(ptr as *mut Felt, note_index.inner)
263    };
264    unsafe {
265        assets.set_len(num_assets);
266    }
267    assets
268}
269
270/// Returns the commitment over all attachments of the output note at `note_index`.
271pub fn get_attachments_commitment(note_index: NoteIdx) -> Word {
272    unsafe {
273        let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
274        extern_output_note_get_attachments_commitment(note_index.inner, ret_area.as_mut_ptr());
275        ret_area.assume_init()
276    }
277}
278
279/// Returns the recipient of the output note at `note_index`.
280pub fn get_recipient(note_index: NoteIdx) -> Recipient {
281    unsafe {
282        let mut ret_area = ::core::mem::MaybeUninit::<Recipient>::uninit();
283        extern_output_note_get_recipient(note_index.inner, ret_area.as_mut_ptr());
284        ret_area.assume_init()
285    }
286}
287
288/// Returns the attachment and metadata header of the output note at `note_index`.
289pub fn get_metadata(note_index: NoteIdx) -> NoteMetadata {
290    unsafe {
291        let mut ret_area = ::core::mem::MaybeUninit::<NoteMetadata>::uninit();
292        extern_output_note_get_metadata(note_index.inner, ret_area.as_mut_ptr());
293        ret_area.assume_init()
294    }
295}
296
297/// Searches the output note metadata for `attachment_scheme`.
298pub fn find_attachment(note_index: NoteIdx, attachment_scheme: Felt) -> AttachmentLocation {
299    unsafe {
300        let mut ret_area = ::core::mem::MaybeUninit::<AttachmentLocation>::uninit();
301        extern_output_note_find_attachment(
302            attachment_scheme,
303            note_index.inner,
304            ret_area.as_mut_ptr(),
305        );
306        ret_area.assume_init()
307    }
308}
309
310/// Writes attachment commitments to memory and returns them as protocol words.
311pub fn write_attachment_commitments_to_memory(note_index: NoteIdx) -> Vec<Word> {
312    let mut commitments: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENTS_PER_NOTE);
313    let num_attachments = unsafe {
314        let ptr = (commitments.as_mut_ptr() as usize) / 4;
315        extern_output_note_write_attachment_commitments_to_memory(
316            ptr as *mut Felt,
317            note_index.inner,
318        )
319    };
320    assert!(
321        num_attachments <= MAX_ATTACHMENTS_PER_NOTE,
322        "note cannot contain more than {MAX_ATTACHMENTS_PER_NOTE} attachments"
323    );
324    unsafe {
325        commitments.set_len(num_attachments);
326    }
327    commitments
328}
329
330/// Writes the selected output-note attachment to memory and returns it as protocol words.
331pub fn write_attachment_to_memory(note_index: NoteIdx, attachment_idx: Felt) -> Vec<Word> {
332    let mut attachment: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENT_WORDS);
333    let num_words = unsafe {
334        let ptr = (attachment.as_mut_ptr() as usize) / 4;
335        extern_output_note_write_attachment_to_memory(
336            ptr as *mut Felt,
337            attachment_idx,
338            note_index.inner,
339        )
340    };
341    assert!(
342        num_words <= MAX_ATTACHMENT_WORDS,
343        "note attachment cannot contain more than {MAX_ATTACHMENT_WORDS} words"
344    );
345    unsafe {
346        attachment.set_len(num_words);
347    }
348    attachment
349}