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