miden_stdlib_sys/intrinsics/
felt.rs

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