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