Skip to main content

miden_field/
lib.rs

1//! A unified `Felt` for on-chain and off-chain Miden Rust code.
2//!
3//! This crate provides a single `Felt` type that can be used in both on-chain (Wasm) and off-chain
4//! (native) Rust code:
5//! - When targeting the Miden VM via Wasm, `Felt` is backed by an on-chain felt.
6//! - Otherwise, `Felt` is backed by a felt (`miden-core`'s field element).
7
8#![no_std]
9#![deny(warnings)]
10
11use core::{fmt, hash::Hash};
12
13/// The field modulus, `2^64 - 2^32 + 1`.
14pub const MODULUS: u64 = 0xffff_ffff_0000_0001;
15
16/// Errors returned by [`Felt::new`].
17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
18pub enum FeltError {
19    /// The provided value was not a valid canonical felt.
20    InvalidValue,
21}
22
23/// A crate-local trait capturing the API surface shared by all `Felt` representations.
24///
25/// This is used to ensure the on-chain and off-chain implementations don't drift in the common
26/// "core" operations, and that required operator traits are implemented consistently.
27pub(crate) trait FeltImpl:
28    Copy
29    + Clone
30    + fmt::Debug
31    + fmt::Display
32    + Eq
33    + Ord
34    + Hash
35    + core::ops::Add<Output = Self>
36    + core::ops::Sub<Output = Self>
37    + core::ops::Mul<Output = Self>
38    + core::ops::Div<Output = Self>
39    + core::ops::Neg<Output = Self>
40    + core::ops::AddAssign
41    + core::ops::SubAssign
42    + core::ops::MulAssign
43    + core::ops::DivAssign
44{
45    /// Creates a `Felt` from `value`.
46    ///
47    /// # Panics
48    ///
49    /// Panics if `value > Felt::M`.
50    fn from_u64_unchecked(value: u64) -> Self;
51
52    /// Creates a `Felt` from a `u32` value.
53    fn from_u32(value: u32) -> Self;
54
55    /// Returns the canonical `u64` value of this felt.
56    fn as_u64(self) -> u64;
57
58    /// Returns true if this felt is odd.
59    fn is_odd(self) -> bool;
60
61    /// Returns `self^-1`. Fails if `self = 0`.
62    fn inv(self) -> Self;
63
64    /// Returns `2^self`. Fails if `self > 63`.
65    fn pow2(self) -> Self;
66
67    /// Returns `self^other`.
68    fn exp(self, other: Self) -> Self;
69}
70
71#[cfg(all(target_family = "wasm", miden))]
72mod wasm32;
73#[cfg(all(target_family = "wasm", miden))]
74pub use wasm32::Felt;
75
76#[cfg(not(all(target_family = "wasm", miden)))]
77mod native;
78#[cfg(not(all(target_family = "wasm", miden)))]
79pub use native::Felt;
80
81impl Felt {
82    /// Field modulus = 2^64 - 2^32 + 1.
83    pub const M: u64 = MODULUS;
84
85    /// Creates a `Felt` from `value` without range checks.
86    #[inline(always)]
87    pub fn from_u64_unchecked(value: u64) -> Self {
88        <Self as FeltImpl>::from_u64_unchecked(value)
89    }
90
91    /// Creates a `Felt` from a `u32` value.
92    #[inline(always)]
93    pub fn from_u32(value: u32) -> Self {
94        <Self as FeltImpl>::from_u32(value)
95    }
96
97    /// Creates a `Felt` from `value`, returning an error if it is out of range.
98    #[inline(always)]
99    pub fn new(value: u64) -> Result<Self, FeltError> {
100        if value >= Self::M {
101            Err(FeltError::InvalidValue)
102        } else {
103            Ok(Self::from_u64_unchecked(value))
104        }
105    }
106
107    /// Returns the canonical `u64` value of this felt.
108    #[inline(always)]
109    pub fn as_u64(self) -> u64 {
110        <Self as FeltImpl>::as_u64(self)
111    }
112
113    /// Returns true if this felt is odd.
114    #[inline(always)]
115    pub fn is_odd(self) -> bool {
116        <Self as FeltImpl>::is_odd(self)
117    }
118
119    /// Returns `self^-1`. Fails if `self = 0`.
120    #[inline(always)]
121    pub fn inv(self) -> Self {
122        <Self as FeltImpl>::inv(self)
123    }
124
125    /// Returns `2^self`. Fails if `self > 63`.
126    #[inline(always)]
127    pub fn pow2(self) -> Self {
128        <Self as FeltImpl>::pow2(self)
129    }
130
131    /// Returns `self^other`.
132    #[inline(always)]
133    pub fn exp(self, other: Self) -> Self {
134        <Self as FeltImpl>::exp(self, other)
135    }
136}