Skip to main content

miden_base_sys/bindings/
types.rs

1extern crate alloc;
2
3use alloc::vec::Vec;
4
5use miden_field_repr::FromFeltRepr;
6use miden_stdlib_sys::{Digest, Felt, Word, hash_elements, intrinsics::crypto::merge};
7
8/// Unique identifier for a Miden account, composed of two field elements.
9#[derive(Copy, Clone, Debug, PartialEq, Eq, FromFeltRepr)]
10pub struct AccountId {
11    pub prefix: Felt,
12    pub suffix: Felt,
13}
14
15impl AccountId {
16    /// Creates a new AccountId from prefix and suffix Felt values.
17    pub fn new(prefix: Felt, suffix: Felt) -> Self {
18        Self { prefix, suffix }
19    }
20}
21
22/// A fungible or a non-fungible asset.
23///
24/// All assets are encoded using a single word (4 elements) such that it is easy to determine the
25/// type of an asset both inside and outside Miden VM. Specifically:
26///
27/// Element 1 of the asset will be:
28/// - ZERO for a fungible asset.
29/// - non-ZERO for a non-fungible asset.
30///
31/// Element 3 of both asset types is the prefix of an
32/// [`AccountId`], which can be used to distinguish assets.
33///
34/// The methodology for constructing fungible and non-fungible assets is described below.
35///
36/// # Fungible assets
37///
38/// - A fungible asset's data layout is: `[amount, 0, faucet_id_suffix, faucet_id_prefix]`.
39///
40/// # Non-fungible assets
41///
42/// - A non-fungible asset's data layout is: `[hash0, hash1, hash2, faucet_id_prefix]`.
43///
44/// The 4 elements of non-fungible assets are computed as follows:
45/// - First the asset data is hashed. This compresses an asset of an arbitrary length to 4 field
46///   elements: `[hash0, hash1, hash2, hash3]`.
47/// - `hash3` is then replaced with the prefix of the faucet ID (`faucet_id_prefix`) which issues
48///   the asset: `[hash0, hash1, hash2, faucet_id_prefix]`.
49///
50#[derive(Copy, Clone, Debug, PartialEq, Eq)]
51#[repr(transparent)]
52pub struct Asset {
53    pub inner: Word,
54}
55
56impl Asset {
57    pub fn new(word: impl Into<Word>) -> Self {
58        Asset { inner: word.into() }
59    }
60
61    pub fn as_word(&self) -> &Word {
62        &self.inner
63    }
64
65    #[inline]
66    pub(crate) fn reverse(&self) -> Self {
67        Self {
68            inner: self.inner.reverse(),
69        }
70    }
71}
72
73impl From<Word> for Asset {
74    fn from(value: Word) -> Self {
75        Self::new(value)
76    }
77}
78
79impl From<[Felt; 4]> for Asset {
80    fn from(value: [Felt; 4]) -> Self {
81        Asset::new(Word::from(value))
82    }
83}
84
85impl From<Asset> for Word {
86    fn from(val: Asset) -> Self {
87        val.inner
88    }
89}
90
91impl AsRef<Word> for Asset {
92    fn as_ref(&self) -> &Word {
93        &self.inner
94    }
95}
96
97#[derive(Clone, Debug, PartialEq, Eq)]
98#[repr(transparent)]
99pub struct Recipient {
100    pub inner: Word,
101}
102
103impl Recipient {
104    /// Computes a recipient digest from the provided components.
105    ///
106    /// This matches the Miden protocol note recipient digest:
107    /// `hash(hash(hash(serial_num, [0; 4]), script_root), inputs_commitment)`.
108    ///
109    /// Where `inputs_commitment` is the RPO256 hash of the provided `inputs`.
110    pub fn compute(serial_num: Word, script_digest: Digest, inputs: Vec<Felt>) -> Self {
111        let empty_word = Word::from_u64_unchecked(0, 0, 0, 0);
112
113        let serial_num_hash = merge([Digest::from_word(serial_num), Digest::from_word(empty_word)]);
114        let merge_script = merge([serial_num_hash, script_digest]);
115        let digest: Word = merge([merge_script, hash_elements(inputs)]).into();
116
117        Self { inner: digest }
118    }
119}
120
121/// The note metadata returned by `*_note::get_metadata` procedures.
122///
123/// In the Miden protocol, metadata retrieval returns both the note attachment and the metadata
124/// header as separate words.
125#[derive(Copy, Clone, Debug, PartialEq, Eq)]
126#[repr(C)]
127pub struct NoteMetadata {
128    /// The attachment of the note.
129    pub attachment: Word,
130    /// The metadata header of the note.
131    pub header: Word,
132}
133
134impl NoteMetadata {
135    /// Creates a new [`NoteMetadata`] from attachment and header.
136    pub fn new(attachment: Word, header: Word) -> Self {
137        Self { attachment, header }
138    }
139
140    #[inline]
141    pub(crate) fn reverse(self) -> Self {
142        Self {
143            attachment: self.attachment.reverse(),
144            header: self.header.reverse(),
145        }
146    }
147}
148
149impl From<[Felt; 4]> for Recipient {
150    fn from(value: [Felt; 4]) -> Self {
151        Recipient {
152            inner: Word::from(value),
153        }
154    }
155}
156
157impl From<Word> for Recipient {
158    fn from(value: Word) -> Self {
159        Recipient { inner: value }
160    }
161}
162
163#[derive(Clone, Copy, Debug, PartialEq, Eq)]
164#[repr(transparent)]
165pub struct Tag {
166    pub inner: Felt,
167}
168
169impl From<Felt> for Tag {
170    fn from(value: Felt) -> Self {
171        Tag { inner: value }
172    }
173}
174
175#[derive(Clone, Copy, Debug, PartialEq, Eq)]
176#[repr(transparent)]
177pub struct NoteIdx {
178    pub inner: Felt,
179}
180
181#[derive(Clone, Copy, Debug, PartialEq, Eq)]
182#[repr(transparent)]
183pub struct NoteType {
184    pub inner: Felt,
185}
186
187impl From<Felt> for NoteType {
188    fn from(value: Felt) -> Self {
189        NoteType { inner: value }
190    }
191}
192
193/// The partial hash of a storage slot name.
194///
195/// A slot id consists of two field elements: a `prefix` and a `suffix`.
196///
197/// Slot ids uniquely identify slots in account storage and are used by the host functions exposed
198/// via `miden::protocol::*`.
199#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
200pub struct StorageSlotId {
201    suffix: Felt,
202    prefix: Felt,
203}
204
205impl StorageSlotId {
206    /// Creates a new [`StorageSlotId`] from the provided felts.
207    ///
208    /// Note: this constructor takes `(suffix, prefix)` to match the values returned by
209    /// `miden_protocol::account::StorageSlotId::{suffix,prefix}`.
210    pub fn new(suffix: Felt, prefix: Felt) -> Self {
211        Self { suffix, prefix }
212    }
213
214    /// Creates a new [`StorageSlotId`] from the provided felts in host-call order.
215    ///
216    /// Host functions take the `prefix` first and then the `suffix`.
217    pub fn from_prefix_suffix(prefix: Felt, suffix: Felt) -> Self {
218        Self { suffix, prefix }
219    }
220
221    /// Returns the `(prefix, suffix)` pair in host-call order.
222    pub fn to_prefix_suffix(&self) -> (Felt, Felt) {
223        (self.prefix, self.suffix)
224    }
225
226    /// Returns the suffix of the [`StorageSlotId`].
227    pub fn suffix(&self) -> Felt {
228        self.suffix
229    }
230
231    /// Returns the prefix of the [`StorageSlotId`].
232    pub fn prefix(&self) -> Felt {
233        self.prefix
234    }
235}