miden-base-sys 0.15.0

Miden rollup Rust bingings and MASM library
Documentation
extern crate alloc;
use alloc::vec::Vec;

use miden_stdlib_sys::{Felt, Word, WordAligned};

use super::{
    MAX_ATTACHMENT_WORDS, MAX_ATTACHMENTS_PER_NOTE, assert_attachment_count,
    assert_attachment_word_count,
    types::{
        Asset, NoteId, NoteIdx, NoteMetadata, NoteType, RawCommitmentWithCount, RawFoundIndex,
        Recipient, Tag,
    },
};

#[allow(improper_ctypes)]
unsafe extern "C" {
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::create"]
    pub fn extern_output_note_create(
        tag: Tag,
        note_type: NoteType,
        recipient_f0: Felt,
        recipient_f1: Felt,
        recipient_f2: Felt,
        recipient_f3: Felt,
    ) -> NoteIdx;
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::add_asset"]
    pub fn extern_output_note_add_asset(
        asset_id_f0: Felt,
        asset_id_f1: Felt,
        asset_id_f2: Felt,
        asset_id_f3: Felt,
        asset_value_f0: Felt,
        asset_value_f1: Felt,
        asset_value_f2: Felt,
        asset_value_f3: Felt,
        note_idx: NoteIdx,
    );
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::get_assets_info"]
    pub(crate) fn extern_output_note_get_assets_info(
        note_index: Felt,
        ptr: *mut RawCommitmentWithCount,
    );
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::get_assets"]
    pub fn extern_output_note_get_assets(dest_ptr: *mut Felt, note_index: Felt) -> usize;
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::get_attachments_commitment"]
    pub fn extern_output_note_get_attachments_commitment(note_index: Felt, ptr: *mut Word);
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::get_recipient"]
    pub fn extern_output_note_get_recipient(note_index: Felt, ptr: *mut Recipient);
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::get_metadata"]
    pub fn extern_output_note_get_metadata(note_index: Felt, ptr: *mut NoteMetadata);
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::add_word_attachment"]
    pub fn extern_output_note_add_word_attachment(
        attachment_scheme: Felt,
        attachment_f0: Felt,
        attachment_f1: Felt,
        attachment_f2: Felt,
        attachment_f3: Felt,
        note_idx: NoteIdx,
    );
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::add_attachment"]
    pub fn extern_output_note_add_attachment(
        attachment_scheme: Felt,
        attachment_f0: Felt,
        attachment_f1: Felt,
        attachment_f2: Felt,
        attachment_f3: Felt,
        note_idx: NoteIdx,
    );
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::add_attachment_from_memory"]
    pub fn extern_output_note_add_attachment_from_memory(
        attachment_scheme: Felt,
        num_words: usize,
        attachment_ptr: *const Felt,
        note_idx: NoteIdx,
    );
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::find_attachment"]
    pub(crate) fn extern_output_note_find_attachment(
        attachment_scheme: Felt,
        note_index: Felt,
        ptr: *mut RawFoundIndex,
    );
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::write_attachment_commitments_to_memory"]
    pub fn extern_output_note_write_attachment_commitments_to_memory(
        dest_ptr: *mut Felt,
        note_index: Felt,
    ) -> usize;
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::write_attachment_to_memory"]
    pub fn extern_output_note_write_attachment_to_memory(
        dest_ptr: *mut Felt,
        attachment_idx: Felt,
        note_index: Felt,
    ) -> usize;
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::compute_note_id"]
    fn extern_output_note_compute_note_id(note_idx: Felt, ptr: *mut NoteId);
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::seal"]
    fn extern_output_note_seal(note_index: Felt);
    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
    #[link_name = "miden::protocol::output_note::is_sealed"]
    fn extern_output_note_is_sealed(note_index: Felt) -> Felt;
}

/// Creates a new output note and returns its index.
///
/// # Examples
///
/// Create a note and add a single asset to it:
///
/// ```rust,ignore
/// // before using `Vec`/`vec!`.
/// extern crate alloc;
///
/// use miden::{felt, note, output_note, Asset, NoteType, Tag, Word};
///
/// // Values used to derive the note recipient.
/// let serial_num = Word::from_u64_unchecked(1, 2, 3, 4);
/// let note_script_root = Word::from_u64_unchecked(0, 0, 0, 0);
///
/// let storage = alloc::vec![felt!(0); 2];
/// let recipient = note::build_recipient(serial_num, note_script_root, storage);
///
/// let tag = Tag::from(felt!(0));
/// let note_type = NoteType::from(felt!(1)); // public note type (0b01)
///
/// let note_idx = output_note::create(tag, note_type, recipient);
/// output_note::add_asset(
///     Asset::new(
///         [felt!(0), felt!(0), felt!(0), felt!(1)],
///         [felt!(1), felt!(0), felt!(0), felt!(0)],
///     ),
///     note_idx,
/// );
/// ```
pub fn create(tag: Tag, note_type: NoteType, recipient: Recipient) -> NoteIdx {
    unsafe {
        extern_output_note_create(
            tag,
            note_type,
            recipient.inner[0],
            recipient.inner[1],
            recipient.inner[2],
            recipient.inner[3],
        )
    }
}

/// Adds a single-word attachment to the output note specified by `note_idx`.
pub fn add_word_attachment(note_idx: NoteIdx, attachment_scheme: Felt, attachment: Word) {
    unsafe {
        extern_output_note_add_word_attachment(
            attachment_scheme,
            attachment[0],
            attachment[1],
            attachment[2],
            attachment[3],
            note_idx,
        );
    }
}

/// Adds an attachment commitment to the output note specified by `note_idx`.
///
/// The advice map must contain an entry for the attachment elements committed to by `attachment`.
pub fn add_attachment(note_idx: NoteIdx, attachment_scheme: Felt, attachment: Word) {
    unsafe {
        extern_output_note_add_attachment(
            attachment_scheme,
            attachment[0],
            attachment[1],
            attachment[2],
            attachment[3],
            note_idx,
        );
    }
}

/// Adds a multi-word attachment from linear memory to the output note specified by `note_idx`.
///
/// Panics if `attachment` is empty or contains more than `MAX_ATTACHMENT_WORDS` (256) words;
/// the kernel rejects both.
pub fn add_attachment_from_memory(note_idx: NoteIdx, attachment_scheme: Felt, attachment: &[Word]) {
    assert!(!attachment.is_empty(), "note attachment cannot be empty");
    assert_attachment_word_count(attachment.len());
    let ptr = (attachment.as_ptr().addr() / 4) as u32;

    unsafe {
        extern_output_note_add_attachment_from_memory(
            attachment_scheme,
            attachment.len(),
            ptr as *const Felt,
            note_idx,
        );
    }
}

/// Adds the asset to the output note specified by `note_idx`.
///
/// # Examples
///
/// ```rust,ignore
/// use miden::{felt, output_note, Asset, NoteIdx, Word};
///
/// // `note_idx` is returned by `output_note::create(...)`.
/// let note_idx: NoteIdx = /* ... */
///
/// let asset = Asset::new(
///     [felt!(0), felt!(0), felt!(0), felt!(1)],
///     [felt!(1), felt!(0), felt!(0), felt!(0)],
/// );
/// output_note::add_asset(asset, note_idx);
/// ```
pub fn add_asset(asset: Asset, note_idx: NoteIdx) {
    let id = asset.id.inner;
    unsafe {
        extern_output_note_add_asset(
            id[0],
            id[1],
            id[2],
            id[3],
            asset.value[0],
            asset.value[1],
            asset.value[2],
            asset.value[3],
            note_idx,
        );
    }
}

/// Seals the output note at `note_index`, so that its assets and attachments can no longer be
/// changed for the rest of the transaction.
///
/// Sealing an already sealed note has no effect.
///
/// # Panics
///
/// Panics if the active account is not the native account, or if `note_index` is out of bounds
/// for the transaction's output notes.
pub fn seal(note_index: NoteIdx) {
    unsafe { extern_output_note_seal(note_index.inner) }
}

/// Returns `true` if the output note at `note_index` is sealed against asset and attachment
/// changes.
///
/// # Panics
///
/// Panics if `note_index` is out of bounds for the transaction's output notes.
pub fn is_sealed(note_index: NoteIdx) -> bool {
    unsafe { extern_output_note_is_sealed(note_index.inner) != Felt::new(0).unwrap() }
}

/// Contains summary information about the assets of an output note.
pub struct OutputNoteAssetsInfo {
    pub commitment: Word,
    pub num_assets: u32,
}

/// Retrieves the assets commitment and asset count for the output note at `note_index`.
pub fn get_assets_info(note_index: NoteIdx) -> OutputNoteAssetsInfo {
    unsafe {
        let mut ret_area =
            WordAligned::new(::core::mem::MaybeUninit::<RawCommitmentWithCount>::uninit());
        extern_output_note_get_assets_info(note_index.inner, ret_area.as_mut_ptr());
        let raw = ret_area.into_inner().assume_init();
        OutputNoteAssetsInfo {
            commitment: raw.commitment,
            num_assets: raw.num_items(),
        }
    }
}

/// Returns the assets contained in the output note at `note_index`.
pub fn get_assets(note_index: NoteIdx) -> Vec<Asset> {
    const MAX_ASSETS: usize = 256;
    let mut assets: Vec<Asset> = Vec::with_capacity(MAX_ASSETS);
    let num_assets = unsafe {
        let ptr = (assets.as_mut_ptr() as usize) / 4;
        extern_output_note_get_assets(ptr as *mut Felt, note_index.inner)
    };
    unsafe {
        assets.set_len(num_assets);
    }
    assets
}

/// Returns the commitment over all attachments of the output note at `note_index`.
pub fn get_attachments_commitment(note_index: NoteIdx) -> Word {
    unsafe {
        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
        extern_output_note_get_attachments_commitment(note_index.inner, ret_area.as_mut_ptr());
        ret_area.into_inner().assume_init()
    }
}

/// Returns the recipient of the output note at `note_index`.
pub fn get_recipient(note_index: NoteIdx) -> Recipient {
    unsafe {
        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Recipient>::uninit());
        extern_output_note_get_recipient(note_index.inner, ret_area.as_mut_ptr());
        ret_area.into_inner().assume_init()
    }
}

/// Returns the metadata header of the output note at `note_index`.
pub fn get_metadata(note_index: NoteIdx) -> NoteMetadata {
    unsafe {
        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<NoteMetadata>::uninit());
        extern_output_note_get_metadata(note_index.inner, ret_area.as_mut_ptr());
        ret_area.into_inner().assume_init()
    }
}

/// Searches the output note metadata for `attachment_scheme`.
pub fn find_attachment(note_index: NoteIdx, attachment_scheme: Felt) -> Option<u32> {
    unsafe {
        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<RawFoundIndex>::uninit());
        extern_output_note_find_attachment(
            attachment_scheme,
            note_index.inner,
            ret_area.as_mut_ptr(),
        );
        ret_area.into_inner().assume_init().into_attachment_index()
    }
}

/// Returns the attachment commitments of the output note at `note_index`.
///
/// The name mirrors the kernel procedure, which fills the buffer this function returns.
pub fn write_attachment_commitments_to_memory(note_index: NoteIdx) -> Vec<Word> {
    let mut commitments: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENTS_PER_NOTE);
    let num_attachments = unsafe {
        let ptr = (commitments.as_mut_ptr() as usize) / 4;
        extern_output_note_write_attachment_commitments_to_memory(
            ptr as *mut Felt,
            note_index.inner,
        )
    };
    assert_attachment_count(num_attachments);
    unsafe {
        commitments.set_len(num_attachments);
    }
    commitments
}

/// Returns the attachment at `attachment_idx` of the output note at `note_index` as protocol
/// words.
///
/// The name mirrors the kernel procedure, which fills the buffer this function returns.
pub fn write_attachment_to_memory(note_index: NoteIdx, attachment_idx: u32) -> Vec<Word> {
    let mut attachment: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENT_WORDS);
    let num_words = unsafe {
        let ptr = (attachment.as_mut_ptr() as usize) / 4;
        extern_output_note_write_attachment_to_memory(
            ptr as *mut Felt,
            Felt::from_u32(attachment_idx),
            note_index.inner,
        )
    };
    assert_attachment_word_count(num_words);
    unsafe {
        attachment.set_len(num_words);
    }
    attachment
}

/// Computes the ID of the output note at `note_index`.
///
/// The ID is only final once the note has been fully constructed, that is, once all of its assets
/// and attachments have been added.
///
/// # Panics
///
/// Panics if `note_index` is out of bounds for the transaction's output notes.
pub fn compute_note_id(note_index: NoteIdx) -> NoteId {
    unsafe {
        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<NoteId>::uninit());
        extern_output_note_compute_note_id(note_index.inner, ret_area.as_mut_ptr());
        ret_area.into_inner().assume_init()
    }
}