miden_stdlib_sys/intrinsics/
felt.rs

1use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
2
3unsafe extern "C" {
4    #[link_name = "intrinsics::felt::from_u64_unchecked"]
5    fn extern_from_u64_unchecked(value: u64) -> Felt;
6
7    #[link_name = "intrinsics::felt::from_u32"]
8    fn extern_from_u32(value: u32) -> Felt;
9
10    #[link_name = "intrinsics::felt::as_u64"]
11    fn extern_as_u64(felt: Felt) -> u64;
12
13    #[link_name = "intrinsics::felt::sub"]
14    fn extern_sub(a: Felt, b: Felt) -> Felt;
15
16    #[link_name = "intrinsics::felt::mul"]
17    fn extern_mul(a: Felt, b: Felt) -> Felt;
18
19    #[link_name = "intrinsics::felt::div"]
20    fn extern_div(a: Felt, b: Felt) -> Felt;
21
22    #[link_name = "intrinsics::felt::neg"]
23    fn extern_neg(a: Felt) -> Felt;
24
25    #[link_name = "intrinsics::felt::inv"]
26    fn extern_inv(a: Felt) -> Felt;
27
28    #[link_name = "intrinsics::felt::pow2"]
29    fn extern_pow2(a: Felt) -> Felt;
30
31    #[link_name = "intrinsics::felt::exp"]
32    fn extern_exp(a: Felt, b: Felt) -> Felt;
33
34    #[link_name = "intrinsics::felt::eq"]
35    fn extern_eq(a: Felt, b: Felt) -> i32;
36
37    #[link_name = "intrinsics::felt::gt"]
38    fn extern_gt(a: Felt, b: Felt) -> i32;
39
40    #[link_name = "intrinsics::felt::lt"]
41    fn extern_lt(a: Felt, b: Felt) -> i32;
42
43    #[link_name = "intrinsics::felt::ge"]
44    fn extern_ge(a: Felt, b: Felt) -> i32;
45
46    #[link_name = "intrinsics::felt::le"]
47    fn extern_le(a: Felt, b: Felt) -> i32;
48
49    #[link_name = "intrinsics::felt::is_odd"]
50    fn extern_is_odd(a: Felt) -> i32;
51
52    #[link_name = "intrinsics::felt::assert"]
53    fn extern_assert(a: Felt);
54
55    #[link_name = "intrinsics::felt::assertz"]
56    fn extern_assertz(a: Felt);
57
58    #[link_name = "intrinsics::felt::assert_eq"]
59    fn extern_assert_eq(a: Felt, b: Felt);
60
61    #[link_name = "intrinsics::felt::add"]
62    fn extern_add(a: Felt, b: Felt) -> Felt;
63}
64
65/// Creates a `Felt` from an integer constant checking that it is within the
66/// valid range at compile time.
67#[macro_export]
68macro_rules! felt {
69    // Trigger a compile-time error if the value is not a constant
70    ($value:literal) => {{
71        const VALUE: u64 = $value as u64;
72        // assert!(VALUE <= Felt::M, "Invalid Felt value, must be >= 0 and <= 2^64 - 2^32 + 1");
73        // Temporarily switch to `from_u32` to use `bitcast` and avoid checks.
74        // see https://github.com/0xMiden/compiler/issues/361
75        assert!(VALUE <= u32::MAX as u64, "Invalid value, must be >= 0 and <= 2^32");
76        const VALUE_U32: u32 = $value as u32;
77        Felt::from_u32(VALUE_U32)
78    }};
79}
80
81#[derive(Debug)]
82pub enum FeltError {
83    InvalidValue,
84}
85
86#[repr(transparent)]
87#[derive(Copy, Clone, Debug)]
88pub struct Felt {
89    pub inner: f32,
90}
91
92impl Felt {
93    /// Field modulus = 2^64 - 2^32 + 1
94    pub const M: u64 = 0xffffffff00000001;
95
96    #[inline(always)]
97    pub fn from_u64_unchecked(value: u64) -> Self {
98        unsafe { extern_from_u64_unchecked(value) }
99    }
100
101    #[inline(always)]
102    pub fn from_u32(value: u32) -> Self {
103        unsafe { extern_from_u32(value) }
104    }
105
106    #[inline(always)]
107    pub fn new(value: u64) -> Result<Self, FeltError> {
108        if value > Self::M {
109            Err(FeltError::InvalidValue)
110        } else {
111            Ok(Self::from_u64_unchecked(value))
112        }
113    }
114
115    #[inline(always)]
116    pub fn as_u64(self) -> u64 {
117        unsafe { extern_as_u64(self) }
118    }
119
120    /// Returns true if x is odd and false if x is even
121    #[inline(always)]
122    pub fn is_odd(self) -> bool {
123        unsafe { extern_is_odd(self) != 0 }
124    }
125
126    /// Returns x^-1
127    /// Fails if a=0
128    #[inline(always)]
129    pub fn inv(self) -> Felt {
130        unsafe { extern_inv(self) }
131    }
132
133    /// Returns 2^x
134    /// Fails if x > 63
135    #[inline(always)]
136    pub fn pow2(self) -> Felt {
137        unsafe { extern_pow2(self) }
138    }
139
140    /// Returns a^b
141    #[inline(always)]
142    pub fn exp(self, other: Felt) -> Felt {
143        unsafe { extern_exp(self, other) }
144    }
145}
146
147impl From<Felt> for u64 {
148    fn from(felt: Felt) -> u64 {
149        felt.as_u64()
150    }
151}
152
153impl From<u32> for Felt {
154    fn from(value: u32) -> Self {
155        Self {
156            inner: f32::from_bits(value),
157        }
158    }
159}
160
161impl From<u16> for Felt {
162    fn from(value: u16) -> Self {
163        Self {
164            inner: f32::from_bits(value as u32),
165        }
166    }
167}
168
169impl From<u8> for Felt {
170    fn from(value: u8) -> Self {
171        Self {
172            inner: f32::from_bits(value as u32),
173        }
174    }
175}
176
177#[cfg(target_pointer_width = "32")]
178impl From<usize> for Felt {
179    fn from(value: usize) -> Self {
180        Self {
181            inner: f32::from_bits(value as u32),
182        }
183    }
184}
185
186impl Add for Felt {
187    type Output = Self;
188
189    #[inline(always)]
190    fn add(self, other: Self) -> Self {
191        unsafe { extern_add(self, other) }
192    }
193}
194
195impl AddAssign for Felt {
196    #[inline(always)]
197    fn add_assign(&mut self, other: Self) {
198        *self = *self + other;
199    }
200}
201
202impl Sub for Felt {
203    type Output = Self;
204
205    #[inline(always)]
206    fn sub(self, other: Self) -> Self {
207        unsafe { extern_sub(self, other) }
208    }
209}
210
211impl SubAssign for Felt {
212    #[inline(always)]
213    fn sub_assign(&mut self, other: Self) {
214        *self = *self - other;
215    }
216}
217
218impl Mul for Felt {
219    type Output = Self;
220
221    #[inline(always)]
222    fn mul(self, other: Self) -> Self {
223        unsafe { extern_mul(self, other) }
224    }
225}
226
227impl MulAssign for Felt {
228    #[inline(always)]
229    fn mul_assign(&mut self, other: Self) {
230        *self = *self * other;
231    }
232}
233
234impl Div for Felt {
235    type Output = Self;
236
237    #[inline(always)]
238    fn div(self, other: Self) -> Self {
239        unsafe { extern_div(self, other) }
240    }
241}
242
243impl DivAssign for Felt {
244    #[inline(always)]
245    fn div_assign(&mut self, other: Self) {
246        *self = *self / other;
247    }
248}
249
250impl Neg for Felt {
251    type Output = Self;
252
253    #[inline(always)]
254    fn neg(self) -> Self {
255        unsafe { extern_neg(self) }
256    }
257}
258
259impl PartialEq for Felt {
260    #[inline(always)]
261    fn eq(&self, other: &Self) -> bool {
262        unsafe { extern_eq(*self, *other) == 1 }
263    }
264}
265
266impl Eq for Felt {}
267
268impl PartialOrd for Felt {
269    #[inline(always)]
270    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
271        Some(self.cmp(other))
272    }
273
274    #[inline(always)]
275    fn gt(&self, other: &Self) -> bool {
276        unsafe { extern_gt(*self, *other) != 0 }
277    }
278
279    #[inline(always)]
280    fn ge(&self, other: &Self) -> bool {
281        unsafe { extern_ge(*self, *other) != 0 }
282    }
283
284    #[inline(always)]
285    fn lt(&self, other: &Self) -> bool {
286        unsafe { extern_lt(*other, *self) != 0 }
287    }
288
289    #[inline(always)]
290    fn le(&self, other: &Self) -> bool {
291        unsafe { extern_le(*other, *self) != 0 }
292    }
293}
294
295impl Ord for Felt {
296    #[inline(always)]
297    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
298        if self.lt(other) {
299            core::cmp::Ordering::Less
300        } else if self.gt(other) {
301            core::cmp::Ordering::Greater
302        } else {
303            core::cmp::Ordering::Equal
304        }
305    }
306}
307
308/// Fails if `a` != 1
309#[inline(always)]
310pub fn assert(a: Felt) {
311    unsafe {
312        extern_assert(a);
313    }
314}
315
316/// Fails if `a` != 0
317#[inline(always)]
318pub fn assertz(a: Felt) {
319    unsafe {
320        extern_assertz(a);
321    }
322}
323
324/// Fails if `a` != `b`
325#[inline(always)]
326pub fn assert_eq(a: Felt, b: Felt) {
327    unsafe {
328        extern_assert_eq(a, b);
329    }
330}
331
332// #[cfg(test)]
333// mod tests {
334//     use super::*;
335
336//     #[test]
337//     fn felt_macro_smoke_test() {
338//         let _ = felt!(1);
339//     }
340// }