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
121impl From<[Felt; 4]> for Recipient {
122    fn from(value: [Felt; 4]) -> Self {
123        Recipient {
124            inner: Word::from(value),
125        }
126    }
127}
128
129impl From<Word> for Recipient {
130    fn from(value: Word) -> Self {
131        Recipient { inner: value }
132    }
133}
134
135#[derive(Clone, Copy, Debug, PartialEq, Eq)]
136#[repr(transparent)]
137pub struct Tag {
138    pub inner: Felt,
139}
140
141impl From<Felt> for Tag {
142    fn from(value: Felt) -> Self {
143        Tag { inner: value }
144    }
145}
146
147#[derive(Clone, Copy, Debug, PartialEq, Eq)]
148#[repr(transparent)]
149pub struct NoteIdx {
150    pub inner: Felt,
151}
152
153#[derive(Clone, Copy, Debug, PartialEq, Eq)]
154#[repr(transparent)]
155pub struct NoteType {
156    pub inner: Felt,
157}
158
159impl From<Felt> for NoteType {
160    fn from(value: Felt) -> Self {
161        NoteType { inner: value }
162    }
163}
164
165/// The partial hash of a storage slot name.
166///
167/// A slot id consists of two field elements: a `prefix` and a `suffix`.
168///
169/// Slot ids uniquely identify slots in account storage and are used by the host functions exposed
170/// via `miden::protocol::*`.
171#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
172pub struct StorageSlotId {
173    suffix: Felt,
174    prefix: Felt,
175}
176
177impl StorageSlotId {
178    /// Creates a new [`StorageSlotId`] from the provided felts.
179    ///
180    /// Note: this constructor takes `(suffix, prefix)` to match the values returned by
181    /// `miden_protocol::account::StorageSlotId::{suffix,prefix}`.
182    pub fn new(suffix: Felt, prefix: Felt) -> Self {
183        Self { suffix, prefix }
184    }
185
186    /// Creates a new [`StorageSlotId`] from the provided felts in host-call order.
187    ///
188    /// Host functions take the `prefix` first and then the `suffix`.
189    pub fn from_prefix_suffix(prefix: Felt, suffix: Felt) -> Self {
190        Self { suffix, prefix }
191    }
192
193    /// Returns the `(prefix, suffix)` pair in host-call order.
194    pub fn to_prefix_suffix(&self) -> (Felt, Felt) {
195        (self.prefix, self.suffix)
196    }
197
198    /// Returns the suffix of the [`StorageSlotId`].
199    pub fn suffix(&self) -> Felt {
200        self.suffix
201    }
202
203    /// Returns the prefix of the [`StorageSlotId`].
204    pub fn prefix(&self) -> Felt {
205        self.prefix
206    }
207}