miden_stdlib_sys/intrinsics/
felt.rs1#![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#[macro_export]
68macro_rules! felt {
69 ($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 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 #[inline(always)]
111 pub fn is_odd(self) -> bool {
112 unsafe { extern_is_odd(self) != 0 }
113 }
114
115 #[inline(always)]
118 pub fn inv(self) -> Felt {
119 unsafe { extern_inv(self) }
120 }
121
122 #[inline(always)]
125 pub fn pow2(self) -> Felt {
126 unsafe { extern_pow2(self) }
127 }
128
129 #[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#[inline(always)]
291pub fn assert(a: Felt) {
292 unsafe {
293 extern_assert(a);
294 }
295}
296
297#[inline(always)]
299pub fn assertz(a: Felt) {
300 unsafe {
301 extern_assertz(a);
302 }
303}
304
305#[inline(always)]
307pub fn assert_eq(a: Felt, b: Felt) {
308 unsafe {
309 extern_assert_eq(a, b);
310 }
311}
312
313