1extern crate alloc;
2
3use miden_field_repr::FromFeltRepr;
4use miden_stdlib_sys::{Felt, Word, felt};
5
6pub fn padded_word_from_felt(value: Felt) -> Word {
8 Word::new([value, felt!(0), felt!(0), felt!(0)])
9}
10
11pub fn felt_from_padded_word(value: Word) -> Result<Felt, &'static str> {
13 if value[1] != felt!(0) || value[2] != felt!(0) || value[3] != felt!(0) {
14 return Err("expected zero padding in the trailing three felts");
15 }
16
17 Ok(value[0])
18}
19
20#[derive(Copy, Clone, Debug, PartialEq, Eq, FromFeltRepr)]
22pub struct AccountId {
23 pub prefix: Felt,
24 pub suffix: Felt,
25}
26
27impl AccountId {
28 pub fn new(prefix: Felt, suffix: Felt) -> Self {
30 Self { prefix, suffix }
31 }
32}
33
34#[derive(Copy, Clone)]
37#[repr(C)]
38pub(crate) struct RawAccountId {
39 pub suffix: Felt,
40 pub prefix: Felt,
41}
42
43impl RawAccountId {
44 pub(crate) fn into_account_id(self) -> AccountId {
46 AccountId::new(self.prefix, self.suffix)
47 }
48}
49
50impl From<AccountId> for Word {
51 #[inline]
52 fn from(value: AccountId) -> Self {
53 Word::from([felt!(0), felt!(0), value.suffix, value.prefix])
54 }
55}
56
57impl TryFrom<Word> for AccountId {
58 type Error = &'static str;
59
60 #[inline]
61 fn try_from(value: Word) -> Result<Self, Self::Error> {
62 if value[0] != felt!(0) || value[1] != felt!(0) {
63 return Err("expected zero padding in the upper two felts");
64 }
65
66 Ok(Self {
67 prefix: value[3],
68 suffix: value[2],
69 })
70 }
71}
72
73#[derive(Copy, Clone, Debug, PartialEq, Eq)]
78#[repr(C)]
79pub struct Asset {
80 pub key: Word,
82 pub value: Word,
84}
85
86impl Asset {
87 pub fn new(key: impl Into<Word>, value: impl Into<Word>) -> Self {
89 Self {
90 key: key.into(),
91 value: value.into(),
92 }
93 }
94}
95
96impl From<Asset> for (Word, Word) {
97 fn from(val: Asset) -> Self {
98 (val.key, val.value)
99 }
100}
101
102#[derive(Clone, Debug, PartialEq, Eq)]
104#[repr(transparent)]
105pub struct Recipient {
106 pub inner: Word,
107}
108
109#[derive(Copy, Clone, Debug, PartialEq, Eq)]
115#[repr(C)]
116pub struct NoteMetadata {
117 pub header: Word,
119}
120
121impl NoteMetadata {
122 pub fn new(header: Word) -> Self {
124 Self { header }
125 }
126}
127
128#[derive(Copy, Clone, Debug, PartialEq, Eq)]
130#[repr(C)]
131pub struct AttachmentLocation {
132 pub is_found: Felt,
134 pub index: Felt,
136}
137
138impl AttachmentLocation {
139 #[inline]
141 pub fn found(&self) -> bool {
142 self.is_found != Felt::new(0).unwrap()
143 }
144}
145
146impl From<[Felt; 4]> for Recipient {
147 fn from(value: [Felt; 4]) -> Self {
148 Recipient {
149 inner: Word::from(value),
150 }
151 }
152}
153
154impl From<Word> for Recipient {
155 fn from(value: Word) -> Self {
156 Recipient { inner: value }
157 }
158}
159
160impl From<Recipient> for Word {
161 #[inline]
162 fn from(value: Recipient) -> Self {
163 value.inner
164 }
165}
166
167#[derive(Clone, Copy, Debug, PartialEq, Eq)]
168#[repr(transparent)]
169pub struct Tag {
170 pub inner: Felt,
171}
172
173impl From<Felt> for Tag {
174 fn from(value: Felt) -> Self {
175 Tag { inner: value }
176 }
177}
178
179impl From<Tag> for Word {
180 #[inline]
181 fn from(value: Tag) -> Self {
182 padded_word_from_felt(value.inner)
183 }
184}
185
186impl TryFrom<Word> for Tag {
187 type Error = &'static str;
188
189 #[inline]
190 fn try_from(value: Word) -> Result<Self, Self::Error> {
191 Ok(Tag {
192 inner: felt_from_padded_word(value)?,
193 })
194 }
195}
196
197#[derive(Clone, Copy, Debug, PartialEq, Eq)]
198#[repr(transparent)]
199pub struct NoteIdx {
200 pub inner: Felt,
201}
202
203impl From<NoteIdx> for Word {
204 #[inline]
205 fn from(value: NoteIdx) -> Self {
206 padded_word_from_felt(value.inner)
207 }
208}
209
210impl TryFrom<Word> for NoteIdx {
211 type Error = &'static str;
212
213 #[inline]
214 fn try_from(value: Word) -> Result<Self, Self::Error> {
215 Ok(NoteIdx {
216 inner: felt_from_padded_word(value)?,
217 })
218 }
219}
220
221#[derive(Clone, Copy, Debug, PartialEq, Eq)]
222#[repr(transparent)]
223pub struct NoteType {
224 pub inner: Felt,
225}
226
227impl From<Felt> for NoteType {
228 fn from(value: Felt) -> Self {
229 NoteType { inner: value }
230 }
231}
232
233impl From<NoteType> for Word {
234 #[inline]
235 fn from(value: NoteType) -> Self {
236 padded_word_from_felt(value.inner)
237 }
238}
239
240impl TryFrom<Word> for NoteType {
241 type Error = &'static str;
242
243 #[inline]
244 fn try_from(value: Word) -> Result<Self, Self::Error> {
245 Ok(NoteType {
246 inner: felt_from_padded_word(value)?,
247 })
248 }
249}
250
251#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
258pub struct StorageSlotId {
259 suffix: Felt,
260 prefix: Felt,
261}
262
263impl StorageSlotId {
264 pub fn new(suffix: Felt, prefix: Felt) -> Self {
269 Self { suffix, prefix }
270 }
271
272 pub fn from_prefix_suffix(prefix: Felt, suffix: Felt) -> Self {
276 Self { suffix, prefix }
277 }
278
279 pub fn to_prefix_suffix(&self) -> (Felt, Felt) {
281 (self.prefix, self.suffix)
282 }
283
284 pub fn to_suffix_prefix(&self) -> (Felt, Felt) {
286 (self.suffix, self.prefix)
287 }
288
289 pub fn suffix(&self) -> Felt {
291 self.suffix
292 }
293
294 pub fn prefix(&self) -> Felt {
296 self.prefix
297 }
298}
299
300#[cfg(test)]
301mod tests {
302 use miden_stdlib_sys::{Word, felt};
303
304 use super::{felt_from_padded_word, padded_word_from_felt};
305
306 #[test]
308 fn padded_word_from_felt_zero_pads_trailing_limbs() {
309 assert_eq!(
310 padded_word_from_felt(felt!(7)),
311 Word::new([felt!(7), felt!(0), felt!(0), felt!(0)])
312 );
313 }
314
315 #[test]
317 fn felt_from_padded_word_rejects_non_zero_padding() {
318 let err =
319 felt_from_padded_word(Word::new([felt!(7), felt!(1), felt!(0), felt!(0)])).unwrap_err();
320
321 assert_eq!(err, "expected zero padding in the trailing three felts");
322 }
323
324 #[test]
326 fn felt_padding_helpers_roundtrip() {
327 let value = felt!(42);
328
329 assert_eq!(felt_from_padded_word(padded_word_from_felt(value)), Ok(value));
330 }
331}