Skip to main content

miden_debug_engine/
felt.rs

1use alloc::{
2    string::{String, ToString},
3    vec::Vec,
4};
5
6use miden_core::{Word, field::PrimeField64};
7pub use miden_processor::Felt as RawFelt;
8#[cfg(feature = "proptest")]
9use proptest::{
10    arbitrary::Arbitrary,
11    strategy::{BoxedStrategy, Strategy},
12};
13use serde::Deserialize;
14use smallvec::{SmallVec, smallvec};
15
16pub trait ToMidenRepr {
17    /// Convert this type into its raw byte representation
18    ///
19    /// The order of bytes in the resulting vector should be little-endian, i.e. the least
20    /// significant bytes come first.
21    fn to_bytes(&self) -> SmallVec<[u8; 16]>;
22    /// Convert this type into one or more field elements, where the order of the elements is such
23    /// that the byte representation of `self` is in little-endian order, i.e. the least significant
24    /// bytes come first.
25    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
26        let bytes = self.to_bytes();
27        let num_felts = bytes.len().div_ceil(4);
28        let mut felts = SmallVec::<[RawFelt; 4]>::with_capacity(num_felts);
29        let (chunks, remainder) = bytes.as_chunks::<4>();
30        for chunk in chunks {
31            felts.push(
32                RawFelt::new(u32::from_ne_bytes(*chunk) as u64)
33                    .expect("value exceeds field modulus"),
34            );
35        }
36        if !remainder.is_empty() {
37            let mut chunk = [0u8; 4];
38            for (i, byte) in remainder.iter().enumerate() {
39                chunk[i] = *byte;
40            }
41            felts.push(
42                RawFelt::new(u32::from_ne_bytes(chunk) as u64)
43                    .expect("value exceeds field modulus"),
44            );
45        }
46        felts
47    }
48    /// Convert this type into one or more words, zero-padding as needed, such that:
49    ///
50    /// * The field elements within each word is in little-endian order, i.e. the least significant
51    ///   bytes of come first.
52    /// * Each word, if pushed on the operand stack element-by-element, would leave the element
53    ///   with the most significant bytes on top of the stack (including padding)
54    fn to_words(&self) -> SmallVec<[Word; 1]> {
55        let felts = self.to_felts();
56        let num_words = felts.len().div_ceil(4);
57        let mut words = SmallVec::<[Word; 1]>::with_capacity(num_words);
58        let (chunks, remainder) = felts.as_chunks::<4>();
59        for mut word in chunks.iter().copied() {
60            word.reverse();
61            words.push(Word::new(word));
62        }
63        if !remainder.is_empty() {
64            let mut word = [RawFelt::ZERO; 4];
65            for (i, felt) in remainder.iter().enumerate() {
66                word[i] = *felt;
67            }
68            word.reverse();
69            words.push(Word::new(word));
70        }
71        words
72    }
73
74    /// Push this value on the given operand stack using [Self::to_felts] representation
75    ///
76    /// If pushing arguments for functions compiled from Wasm, consider using
77    /// [`push_wasm_ty_to_operand_stack`] instead.
78    fn push_to_operand_stack(&self, stack: &mut Vec<RawFelt>) {
79        stack.extend(self.to_felts());
80    }
81
82    /// Push this value in its [Self::to_words] representation, on the given stack.
83    ///
84    /// This function is designed for encoding values that will be placed on the advice stack and
85    /// copied into Miden VM memory by the compiler-emitted test harness.
86    ///
87    /// Returns the number of words that were pushed on the stack
88    fn push_words_to_advice_stack(&self, stack: &mut Vec<RawFelt>) -> usize {
89        let words = self.to_words();
90        let num_words = words.len();
91        for word in words.into_iter().rev() {
92            for felt in word.into_iter() {
93                stack.push(felt);
94            }
95        }
96        num_words
97    }
98}
99
100pub trait FromMidenRepr: Sized {
101    /// Returns the size of this type as encoded by [ToMidenRepr::to_felts]
102    fn size_in_felts() -> usize;
103    /// Extract a value of this type from `bytes`, where:
104    ///
105    /// * It is assumed that bytes is always padded out to 4 byte alignment
106    /// * It is assumed that the bytes are in little-endian order, as encoded by [ToMidenRepr]
107    fn from_bytes(bytes: &[u8]) -> Self;
108    /// Extract a value of this type as encoded in a vector of field elements, where:
109    ///
110    /// * The order of the field elements is little-endian, i.e. the element holding the least
111    ///   significant bytes comes first.
112    fn from_felts(felts: &[RawFelt]) -> Self {
113        let mut bytes = SmallVec::<[u8; 16]>::with_capacity(felts.len() * 4);
114        for felt in felts {
115            let chunk = (felt.as_canonical_u64() as u32).to_ne_bytes();
116            bytes.extend(chunk);
117        }
118        Self::from_bytes(&bytes)
119    }
120    /// Extract a value of this type as encoded in a vector of words, where:
121    ///
122    /// * The order of the words is little-endian, i.e. the word holding the least significant
123    ///   bytes comes first.
124    /// * The order of the field elements in each word is in big-endian order, i.e. the element
125    ///   with the most significant byte is at the start of the word, and the element with the
126    ///   least significant byte is at the end of the word. This corresponds to the order in
127    ///   which elements are placed on the operand stack when preparing to read or write them
128    ///   from Miden's memory.
129    fn from_words(words: &[Word]) -> Self {
130        let mut felts = SmallVec::<[RawFelt; 4]>::with_capacity(words.len() * 4);
131        for word in words {
132            for felt in word.iter().copied().rev() {
133                felts.push(felt);
134            }
135        }
136        Self::from_felts(&felts)
137    }
138
139    /// Pop a value of this type from `stack` based on the canonical representation of this type
140    /// on the operand stack when writing it to memory (and as read from memory).
141    fn pop_from_stack(stack: &mut Vec<RawFelt>) -> Self {
142        let needed = Self::size_in_felts();
143        let mut felts = SmallVec::<[RawFelt; 4]>::with_capacity(needed);
144        for _ in 0..needed {
145            felts.push(stack.pop().unwrap());
146        }
147        Self::from_felts(&felts)
148    }
149}
150
151impl ToMidenRepr for bool {
152    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
153        smallvec![*self as u8]
154    }
155
156    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
157        smallvec![RawFelt::new(*self as u64).expect("value exceeds field modulus")]
158    }
159
160    fn push_to_operand_stack(&self, stack: &mut Vec<RawFelt>) {
161        stack.push(RawFelt::new(*self as u64).expect("value exceeds field modulus"));
162    }
163}
164
165impl FromMidenRepr for bool {
166    #[inline(always)]
167    fn size_in_felts() -> usize {
168        1
169    }
170
171    fn from_bytes(bytes: &[u8]) -> Self {
172        match bytes[0] {
173            0 => false,
174            1 => true,
175            n => panic!("invalid byte representation for boolean: {n:0x}"),
176        }
177    }
178
179    fn from_felts(felts: &[RawFelt]) -> Self {
180        match felts[0].as_canonical_u64() {
181            0 => false,
182            1 => true,
183            n => panic!("invalid byte representation for boolean: {n:0x}"),
184        }
185    }
186
187    fn pop_from_stack(stack: &mut Vec<RawFelt>) -> Self {
188        match stack.pop().unwrap().as_canonical_u64() {
189            0 => false,
190            1 => true,
191            n => panic!("invalid byte representation for boolean: {n:0x}"),
192        }
193    }
194}
195
196impl ToMidenRepr for u8 {
197    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
198        smallvec![*self]
199    }
200
201    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
202        smallvec![RawFelt::new(*self as u64).expect("value exceeds field modulus")]
203    }
204
205    fn push_to_operand_stack(&self, stack: &mut Vec<RawFelt>) {
206        stack.push(RawFelt::new(*self as u64).expect("value exceeds field modulus"));
207    }
208}
209
210impl FromMidenRepr for u8 {
211    #[inline(always)]
212    fn size_in_felts() -> usize {
213        1
214    }
215
216    #[inline(always)]
217    fn from_bytes(bytes: &[u8]) -> Self {
218        bytes[0]
219    }
220
221    fn from_felts(felts: &[RawFelt]) -> Self {
222        felts[0].as_canonical_u64() as u8
223    }
224
225    fn pop_from_stack(stack: &mut Vec<RawFelt>) -> Self {
226        stack.pop().unwrap().as_canonical_u64() as u8
227    }
228}
229
230impl ToMidenRepr for i8 {
231    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
232        smallvec![*self as u8]
233    }
234
235    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
236        smallvec![RawFelt::new(*self as u8 as u64).expect("value exceeds field modulus")]
237    }
238
239    fn push_to_operand_stack(&self, stack: &mut Vec<RawFelt>) {
240        stack.push(RawFelt::new(*self as u8 as u64).expect("value exceeds field modulus"));
241    }
242}
243
244impl FromMidenRepr for i8 {
245    #[inline(always)]
246    fn size_in_felts() -> usize {
247        1
248    }
249
250    #[inline(always)]
251    fn from_bytes(bytes: &[u8]) -> Self {
252        bytes[0] as i8
253    }
254
255    fn from_felts(felts: &[RawFelt]) -> Self {
256        felts[0].as_canonical_u64() as u8 as i8
257    }
258
259    fn pop_from_stack(stack: &mut Vec<RawFelt>) -> Self {
260        stack.pop().unwrap().as_canonical_u64() as u8 as i8
261    }
262}
263
264impl ToMidenRepr for u16 {
265    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
266        SmallVec::from_slice(&self.to_ne_bytes())
267    }
268
269    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
270        smallvec![RawFelt::new(*self as u64).expect("value exceeds field modulus")]
271    }
272
273    fn push_to_operand_stack(&self, stack: &mut Vec<RawFelt>) {
274        stack.push(RawFelt::new(*self as u64).expect("value exceeds field modulus"));
275    }
276}
277
278impl FromMidenRepr for u16 {
279    #[inline(always)]
280    fn size_in_felts() -> usize {
281        1
282    }
283
284    fn from_bytes(bytes: &[u8]) -> Self {
285        assert!(bytes.len() >= 2);
286        u16::from_ne_bytes([bytes[0], bytes[1]])
287    }
288
289    fn from_felts(felts: &[RawFelt]) -> Self {
290        felts[0].as_canonical_u64() as u16
291    }
292
293    fn pop_from_stack(stack: &mut Vec<RawFelt>) -> Self {
294        stack.pop().unwrap().as_canonical_u64() as u16
295    }
296}
297
298impl ToMidenRepr for i16 {
299    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
300        SmallVec::from_slice(&self.to_ne_bytes())
301    }
302
303    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
304        smallvec![RawFelt::new(*self as u16 as u64).expect("value exceeds field modulus")]
305    }
306
307    fn push_to_operand_stack(&self, stack: &mut Vec<RawFelt>) {
308        stack.push(RawFelt::new(*self as u16 as u64).expect("value exceeds field modulus"));
309    }
310}
311
312impl FromMidenRepr for i16 {
313    #[inline(always)]
314    fn size_in_felts() -> usize {
315        1
316    }
317
318    fn from_bytes(bytes: &[u8]) -> Self {
319        assert!(bytes.len() >= 2);
320        i16::from_ne_bytes([bytes[0], bytes[1]])
321    }
322
323    fn from_felts(felts: &[RawFelt]) -> Self {
324        felts[0].as_canonical_u64() as u16 as i16
325    }
326
327    fn pop_from_stack(stack: &mut Vec<RawFelt>) -> Self {
328        stack.pop().unwrap().as_canonical_u64() as u16 as i16
329    }
330}
331
332impl ToMidenRepr for u32 {
333    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
334        SmallVec::from_slice(&self.to_ne_bytes())
335    }
336
337    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
338        smallvec![RawFelt::new(*self as u64).expect("value exceeds field modulus")]
339    }
340
341    fn push_to_operand_stack(&self, stack: &mut Vec<RawFelt>) {
342        stack.push(RawFelt::new(*self as u64).expect("value exceeds field modulus"));
343    }
344}
345
346impl FromMidenRepr for u32 {
347    #[inline(always)]
348    fn size_in_felts() -> usize {
349        1
350    }
351
352    fn from_bytes(bytes: &[u8]) -> Self {
353        assert!(bytes.len() >= 4);
354        u32::from_ne_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
355    }
356
357    fn from_felts(felts: &[RawFelt]) -> Self {
358        felts[0].as_canonical_u64() as u32
359    }
360
361    fn pop_from_stack(stack: &mut Vec<RawFelt>) -> Self {
362        stack.pop().unwrap().as_canonical_u64() as u32
363    }
364}
365
366impl ToMidenRepr for i32 {
367    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
368        SmallVec::from_slice(&self.to_ne_bytes())
369    }
370
371    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
372        smallvec![RawFelt::new(*self as u32 as u64).expect("value exceeds field modulus")]
373    }
374
375    fn push_to_operand_stack(&self, stack: &mut Vec<RawFelt>) {
376        stack.push(RawFelt::new(*self as u32 as u64).expect("value exceeds field modulus"));
377    }
378}
379
380impl FromMidenRepr for i32 {
381    #[inline(always)]
382    fn size_in_felts() -> usize {
383        1
384    }
385
386    fn from_bytes(bytes: &[u8]) -> Self {
387        assert!(bytes.len() >= 4);
388        i32::from_ne_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])
389    }
390
391    fn from_felts(felts: &[RawFelt]) -> Self {
392        felts[0].as_canonical_u64() as u32 as i32
393    }
394
395    fn pop_from_stack(stack: &mut Vec<RawFelt>) -> Self {
396        stack.pop().unwrap().as_canonical_u64() as u32 as i32
397    }
398}
399
400impl ToMidenRepr for u64 {
401    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
402        SmallVec::from_slice(&self.to_le_bytes())
403    }
404
405    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
406        let lo = (*self as u32) as u64;
407        let hi = *self >> 32;
408        smallvec![
409            RawFelt::new(lo).expect("value exceeds field modulus"),
410            RawFelt::new(hi).expect("value exceeds field modulus"),
411        ]
412    }
413}
414
415impl FromMidenRepr for u64 {
416    #[inline(always)]
417    fn size_in_felts() -> usize {
418        2
419    }
420
421    fn from_bytes(bytes: &[u8]) -> Self {
422        assert!(bytes.len() >= 8);
423        u64::from_le_bytes([
424            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
425        ])
426    }
427
428    fn from_felts(felts: &[RawFelt]) -> Self {
429        assert!(felts.len() >= 2);
430        let lo = felts[0].as_canonical_u64() as u32 as u64;
431        let hi = felts[1].as_canonical_u64() as u32 as u64;
432        lo | (hi << 32)
433    }
434}
435
436impl ToMidenRepr for i64 {
437    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
438        SmallVec::from_slice(&self.to_le_bytes())
439    }
440
441    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
442        (*self as u64).to_felts()
443    }
444}
445
446impl FromMidenRepr for i64 {
447    #[inline(always)]
448    fn size_in_felts() -> usize {
449        2
450    }
451
452    fn from_bytes(bytes: &[u8]) -> Self {
453        u64::from_bytes(bytes) as i64
454    }
455
456    fn from_felts(felts: &[RawFelt]) -> Self {
457        u64::from_felts(felts) as i64
458    }
459}
460
461impl ToMidenRepr for u128 {
462    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
463        SmallVec::from_slice(&self.to_le_bytes())
464    }
465
466    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
467        let lo_lo = RawFelt::new((*self as u32) as u64).expect("value exceeds field modulus");
468        let lo_hi =
469            RawFelt::new(((*self >> 32) as u32) as u64).expect("value exceeds field modulus");
470        let hi_lo =
471            RawFelt::new(((*self >> 64) as u32) as u64).expect("value exceeds field modulus");
472        let hi_hi =
473            RawFelt::new(((*self >> 96) as u32) as u64).expect("value exceeds field modulus");
474        smallvec![lo_lo, lo_hi, hi_lo, hi_hi]
475    }
476}
477
478impl FromMidenRepr for u128 {
479    #[inline(always)]
480    fn size_in_felts() -> usize {
481        4
482    }
483
484    fn from_bytes(bytes: &[u8]) -> Self {
485        assert!(bytes.len() >= 16);
486        u128::from_le_bytes([
487            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
488            bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
489        ])
490    }
491
492    fn from_felts(felts: &[RawFelt]) -> Self {
493        assert!(felts.len() >= 4);
494        let lo_lo = felts[0].as_canonical_u64() as u32 as u128;
495        let lo_hi = felts[1].as_canonical_u64() as u32 as u128;
496        let hi_lo = felts[2].as_canonical_u64() as u32 as u128;
497        let hi_hi = felts[3].as_canonical_u64() as u32 as u128;
498        lo_lo | (lo_hi << 32) | (hi_lo << 64) | (hi_hi << 96)
499    }
500}
501
502impl ToMidenRepr for i128 {
503    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
504        SmallVec::from_slice(&self.to_le_bytes())
505    }
506
507    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
508        (*self as u128).to_felts()
509    }
510}
511
512impl FromMidenRepr for i128 {
513    #[inline(always)]
514    fn size_in_felts() -> usize {
515        4
516    }
517
518    fn from_bytes(bytes: &[u8]) -> Self {
519        u128::from_bytes(bytes) as i128
520    }
521
522    fn from_felts(felts: &[RawFelt]) -> Self {
523        u128::from_felts(felts) as i128
524    }
525}
526
527impl ToMidenRepr for RawFelt {
528    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
529        panic!("field elements have no canonical byte representation")
530    }
531
532    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
533        smallvec![*self]
534    }
535
536    fn to_words(&self) -> SmallVec<[Word; 1]> {
537        let mut word = [RawFelt::ZERO; 4];
538        word[0] = *self;
539        smallvec![Word::new(word)]
540    }
541}
542
543impl FromMidenRepr for RawFelt {
544    #[inline(always)]
545    fn size_in_felts() -> usize {
546        1
547    }
548
549    fn from_bytes(_bytes: &[u8]) -> Self {
550        panic!("field elements have no canonical byte representation")
551    }
552
553    #[inline(always)]
554    fn from_felts(felts: &[RawFelt]) -> Self {
555        felts[0]
556    }
557
558    #[inline(always)]
559    fn from_words(words: &[Word]) -> Self {
560        words[0][0]
561    }
562}
563
564impl ToMidenRepr for Felt {
565    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
566        panic!("field elements have no canonical byte representation")
567    }
568
569    fn to_felts(&self) -> SmallVec<[RawFelt; 4]> {
570        smallvec![self.0]
571    }
572
573    fn to_words(&self) -> SmallVec<[Word; 1]> {
574        let mut word = [RawFelt::ZERO; 4];
575        word[0] = self.0;
576        smallvec![Word::new(word)]
577    }
578}
579
580impl FromMidenRepr for Felt {
581    #[inline(always)]
582    fn size_in_felts() -> usize {
583        1
584    }
585
586    fn from_bytes(_bytes: &[u8]) -> Self {
587        panic!("field elements have no canonical byte representation")
588    }
589
590    #[inline(always)]
591    fn from_felts(felts: &[RawFelt]) -> Self {
592        Felt(felts[0])
593    }
594
595    #[inline(always)]
596    fn from_words(words: &[Word]) -> Self {
597        Felt(words[0][0])
598    }
599}
600
601impl<const N: usize> ToMidenRepr for [u8; N] {
602    #[inline]
603    fn to_bytes(&self) -> SmallVec<[u8; 16]> {
604        SmallVec::from_slice(self)
605    }
606}
607
608impl<const N: usize> FromMidenRepr for [u8; N] {
609    #[inline(always)]
610    fn size_in_felts() -> usize {
611        N.div_ceil(4)
612    }
613
614    fn from_bytes(bytes: &[u8]) -> Self {
615        assert!(bytes.len() >= N, "insufficient bytes");
616        Self::try_from(&bytes[..N]).unwrap()
617    }
618}
619
620impl FromMidenRepr for [Felt; 4] {
621    #[inline(always)]
622    fn size_in_felts() -> usize {
623        4
624    }
625
626    fn from_bytes(_bytes: &[u8]) -> Self {
627        panic!("field elements have no canonical byte representation")
628    }
629
630    #[inline(always)]
631    fn from_felts(felts: &[RawFelt]) -> Self {
632        [Felt(felts[0]), Felt(felts[1]), Felt(felts[2]), Felt(felts[3])]
633    }
634}
635
636/// Convert a byte array to an equivalent vector of words
637///
638/// Given a byte slice laid out like so:
639///
640/// [b0, b1, b2, b3, b4, b5, b6, b7, .., b31]
641///
642/// This will produce a vector of words laid out like so:
643///
644/// [[{b12, ..b15}, {b8..b11}, {b4, ..b7}, {b0, ..b3}], [{b31, ..}, ..]]
645///
646/// In short, it produces words that when placed on the stack and written to memory word-by-word,
647/// the original bytes will be laid out in Miden's memory in the correct order.
648pub fn bytes_to_words(bytes: &[u8]) -> Vec<[RawFelt; 4]> {
649    // 1. Chunk bytes up into felts
650    let (chunks, remainder) = bytes.as_chunks::<4>();
651    let padded_bytes = bytes.len().next_multiple_of(16);
652    let num_felts = padded_bytes / 4;
653    let mut buf = Vec::with_capacity(num_felts);
654    for chunk in chunks {
655        let n = u32::from_ne_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
656        buf.push(n);
657    }
658    // Zero-pad the buffer to nearest whole element
659    if !remainder.is_empty() {
660        let mut n_buf = [0u8; 4];
661        for (i, byte) in remainder.iter().enumerate() {
662            n_buf[i] = *byte;
663        }
664        buf.push(u32::from_ne_bytes(n_buf));
665    }
666    // Zero-pad the buffer to nearest whole word
667    buf.resize(num_felts, 0);
668    // Chunk into words, and push them in largest-address first order
669    let num_words = num_felts / 4;
670    let mut words = Vec::with_capacity(num_words);
671    let (chunks, remainder) = buf.as_chunks::<4>();
672    for chunk in chunks {
673        words.push([
674            RawFelt::new(chunk[3] as u64).expect("value exceeds field modulus"),
675            RawFelt::new(chunk[2] as u64).expect("value exceeds field modulus"),
676            RawFelt::new(chunk[1] as u64).expect("value exceeds field modulus"),
677            RawFelt::new(chunk[0] as u64).expect("value exceeds field modulus"),
678        ]);
679    }
680    if !remainder.is_empty() {
681        let mut word = [RawFelt::ZERO; 4];
682        for (i, n) in remainder.iter().enumerate() {
683            word[i] = RawFelt::new(*n as u64).expect("value exceeds field modulus");
684        }
685        word.reverse();
686        words.push(word);
687    }
688    words
689}
690
691/// Wrapper around `miden_processor::Felt` that implements useful traits that are not implemented
692/// for that type.
693#[derive(Debug, Copy, Clone, PartialEq, Eq)]
694pub struct Felt(pub RawFelt);
695impl Felt {
696    #[inline]
697    pub fn new(value: u64) -> Self {
698        Self(RawFelt::new(value).expect("value exceeds field modulus"))
699    }
700}
701
702impl<'de> Deserialize<'de> for Felt {
703    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
704    where
705        D: serde::Deserializer<'de>,
706    {
707        u64::deserialize(deserializer).and_then(|n| {
708            if n >= RawFelt::ORDER_U64 {
709                Err(serde::de::Error::custom(
710                    "invalid field element value: exceeds the field modulus",
711                ))
712            } else {
713                Ok(Felt(RawFelt::new(n).expect("value exceeds field modulus")))
714            }
715        })
716    }
717}
718
719#[cfg(feature = "std")]
720impl clap::builder::ValueParserFactory for Felt {
721    type Parser = FeltParser;
722
723    fn value_parser() -> Self::Parser {
724        FeltParser
725    }
726}
727
728#[doc(hidden)]
729#[cfg(feature = "std")]
730#[derive(Clone)]
731pub struct FeltParser;
732#[cfg(feature = "std")]
733impl clap::builder::TypedValueParser for FeltParser {
734    type Value = Felt;
735
736    fn parse_ref(
737        &self,
738        _cmd: &clap::Command,
739        _arg: Option<&clap::Arg>,
740        value: &std::ffi::OsStr,
741    ) -> Result<Self::Value, clap::error::Error> {
742        use clap::error::{Error, ErrorKind};
743
744        let value = value.to_str().ok_or_else(|| Error::new(ErrorKind::InvalidUtf8))?.trim();
745        value.parse().map_err(|err| Error::raw(ErrorKind::ValueValidation, err))
746    }
747}
748
749impl core::str::FromStr for Felt {
750    type Err = String;
751
752    fn from_str(s: &str) -> Result<Self, Self::Err> {
753        let value = if let Some(value) = s.strip_prefix("0x") {
754            u64::from_str_radix(value, 16)
755                .map_err(|err| format!("invalid field element value: {err}"))?
756        } else {
757            s.parse::<u64>().map_err(|err| format!("invalid field element value: {err}"))?
758        };
759
760        if value >= RawFelt::ORDER_U64 {
761            Err("invalid field element value: exceeds the field modulus".to_string())
762        } else {
763            Ok(Felt(RawFelt::new(value).expect("value exceeds field modulus")))
764        }
765    }
766}
767
768impl From<Felt> for miden_processor::Felt {
769    fn from(f: Felt) -> Self {
770        f.0
771    }
772}
773
774impl From<bool> for Felt {
775    fn from(b: bool) -> Self {
776        Self(RawFelt::new(b as u64).expect("value exceeds field modulus"))
777    }
778}
779
780impl From<u8> for Felt {
781    fn from(t: u8) -> Self {
782        Self(RawFelt::new(t as u64).expect("value exceeds field modulus"))
783    }
784}
785
786impl From<i8> for Felt {
787    fn from(t: i8) -> Self {
788        Self(RawFelt::new(t as u8 as u64).expect("value exceeds field modulus"))
789    }
790}
791
792impl From<i16> for Felt {
793    fn from(t: i16) -> Self {
794        Self(RawFelt::new(t as u16 as u64).expect("value exceeds field modulus"))
795    }
796}
797
798impl From<u16> for Felt {
799    fn from(t: u16) -> Self {
800        Self(RawFelt::new(t as u64).expect("value exceeds field modulus"))
801    }
802}
803
804impl From<i32> for Felt {
805    fn from(t: i32) -> Self {
806        Self(RawFelt::new(t as u32 as u64).expect("value exceeds field modulus"))
807    }
808}
809
810impl From<u32> for Felt {
811    fn from(t: u32) -> Self {
812        Self(RawFelt::new(t as u64).expect("value exceeds field modulus"))
813    }
814}
815
816impl From<u64> for Felt {
817    fn from(t: u64) -> Self {
818        Self(RawFelt::new(t).expect("value exceeds field modulus"))
819    }
820}
821
822impl From<i64> for Felt {
823    fn from(t: i64) -> Self {
824        Self(RawFelt::new(t as u64).expect("value exceeds field modulus"))
825    }
826}
827
828// Reverse Felt to Rust types conversion
829
830impl From<Felt> for bool {
831    fn from(f: Felt) -> Self {
832        f.0.as_canonical_u64() != 0
833    }
834}
835
836impl From<Felt> for u8 {
837    fn from(f: Felt) -> Self {
838        f.0.as_canonical_u64() as u8
839    }
840}
841
842impl From<Felt> for i8 {
843    fn from(f: Felt) -> Self {
844        f.0.as_canonical_u64() as i8
845    }
846}
847
848impl From<Felt> for u16 {
849    fn from(f: Felt) -> Self {
850        f.0.as_canonical_u64() as u16
851    }
852}
853
854impl From<Felt> for i16 {
855    fn from(f: Felt) -> Self {
856        f.0.as_canonical_u64() as i16
857    }
858}
859
860impl From<Felt> for u32 {
861    fn from(f: Felt) -> Self {
862        f.0.as_canonical_u64() as u32
863    }
864}
865
866impl From<Felt> for i32 {
867    fn from(f: Felt) -> Self {
868        f.0.as_canonical_u64() as i32
869    }
870}
871
872impl From<Felt> for u64 {
873    fn from(f: Felt) -> Self {
874        f.0.as_canonical_u64()
875    }
876}
877
878impl From<Felt> for i64 {
879    fn from(f: Felt) -> Self {
880        f.0.as_canonical_u64() as i64
881    }
882}
883
884#[cfg(feature = "proptest")]
885impl Arbitrary for Felt {
886    type Parameters = ();
887    type Strategy = BoxedStrategy<Self>;
888
889    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
890        (0u64..RawFelt::ORDER_U64)
891            .prop_map(|v| Felt(RawFelt::new(v).expect("value exceeds field modulus")))
892            .boxed()
893    }
894}
895
896/// Converts `value` to its corresponding Wasm ABI type and pushes it to the stack.
897///
898/// It differs from [`ToMidenRepr::push_to_operand_stack`] because it sign-extends `i8` and `i16`
899/// values to `i32` before pushing them to the stack.
900pub fn push_wasm_ty_to_operand_stack<T>(value: T, stack: &mut Vec<RawFelt>)
901where
902    T: ToMidenRepr + num_traits::PrimInt,
903{
904    let ty_size = core::mem::size_of::<T>();
905    if ty_size > 2 {
906        value.push_to_operand_stack(stack);
907        return;
908    }
909
910    let is_signed = T::min_value() < T::zero();
911    // The unwraps below are safe because `value` is at most 16 bits wide.
912    let value_u32 = if is_signed {
913        value.to_i32().unwrap() as u32
914    } else {
915        value.to_u32().unwrap()
916    };
917    value_u32.push_to_operand_stack(stack);
918}
919
920#[cfg(test)]
921mod tests;