miden_stdlib_sys/intrinsics/
felt.rs

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