Skip to main content

miden_precompiles/math/uint/
domain.rs

1//! Fixed uint domains supported by deferred evaluation and generated MASM support.
2
3use miden_core::Felt;
4
5use super::spec::{Limbs, UintSpec};
6use crate::math::{k1_base::K1Base, k1_scalar::K1Scalar, u256::U256};
7
8/// VM-owned store pointer for the U256 wrapping-domain bound (`2^256 - 1`).
9pub const U256_BOUND_PTR: u32 = 1;
10/// VM-owned store pointer for the secp256k1 base-field bound (`p - 1`).
11pub const K1_BASE_BOUND_PTR: u32 = 2;
12/// VM-owned store pointer for the secp256k1 scalar-field bound (`n - 1`).
13pub const K1_SCALAR_BOUND_PTR: u32 = 3;
14
15/// Fixed uint arithmetic domains supported by the native uint precompile.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum UintDomain {
18    /// Arithmetic modulo `2^256`.
19    U256,
20    /// secp256k1 base field.
21    K1Base,
22    /// secp256k1 scalar field.
23    K1Scalar,
24}
25
26impl UintDomain {
27    /// All fixed domains in deterministic precompile initialization order.
28    pub const ALL: [Self; 3] = [Self::U256, Self::K1Base, Self::K1Scalar];
29
30    /// Returns the supported domain for a tag-local id.
31    pub fn from_id(id: Felt) -> Option<Self> {
32        match id {
33            id if id == <U256 as UintSpec>::ID => Some(Self::U256),
34            id if id == <K1Base as UintSpec>::ID => Some(Self::K1Base),
35            id if id == <K1Scalar as UintSpec>::ID => Some(Self::K1Scalar),
36            _ => None,
37        }
38    }
39
40    /// Returns the stable local domain selector retained for host-side metadata.
41    pub fn id(self) -> Felt {
42        match self {
43            Self::U256 => <U256 as UintSpec>::ID,
44            Self::K1Base => <K1Base as UintSpec>::ID,
45            Self::K1Scalar => <K1Scalar as UintSpec>::ID,
46        }
47    }
48
49    /// Returns the VM-owned bound pointer carried in uint `VALUE` tags.
50    pub const fn bound_ptr(self) -> u32 {
51        match self {
52            Self::U256 => U256_BOUND_PTR,
53            Self::K1Base => K1_BASE_BOUND_PTR,
54            Self::K1Scalar => K1_SCALAR_BOUND_PTR,
55        }
56    }
57
58    /// Returns the supported domain for a VM-owned bound pointer.
59    pub const fn from_bound_ptr(ptr: u32) -> Option<Self> {
60        match ptr {
61            U256_BOUND_PTR => Some(Self::U256),
62            K1_BASE_BOUND_PTR => Some(Self::K1Base),
63            K1_SCALAR_BOUND_PTR => Some(Self::K1Scalar),
64            _ => None,
65        }
66    }
67
68    /// Returns the encoded modulus limbs. `[0; 8]` is the `2^256` sentinel.
69    pub fn encoded_modulus(self) -> Limbs {
70        match self {
71            Self::U256 => <U256 as UintSpec>::ENCODED_MODULUS,
72            Self::K1Base => <K1Base as UintSpec>::ENCODED_MODULUS,
73            Self::K1Scalar => <K1Scalar as UintSpec>::ENCODED_MODULUS,
74        }
75    }
76
77    /// Returns whether this domain is declared to be a prime field.
78    pub fn is_prime_field(self) -> bool {
79        match self {
80            Self::U256 => <U256 as UintSpec>::IS_PRIME_FIELD,
81            Self::K1Base => <K1Base as UintSpec>::IS_PRIME_FIELD,
82            Self::K1Scalar => <K1Scalar as UintSpec>::IS_PRIME_FIELD,
83        }
84    }
85
86    /// Returns whether `value` is canonical for this domain.
87    pub fn is_canonical(self, value: &Limbs) -> bool {
88        match self {
89            Self::U256 => U256::is_canonical(value),
90            Self::K1Base => K1Base::is_canonical(value),
91            Self::K1Scalar => K1Scalar::is_canonical(value),
92        }
93    }
94
95    /// Adds two canonical values in this domain.
96    pub fn add(self, lhs: Limbs, rhs: Limbs) -> Limbs {
97        match self {
98            Self::U256 => U256::add(lhs, rhs),
99            Self::K1Base => K1Base::add(lhs, rhs),
100            Self::K1Scalar => K1Scalar::add(lhs, rhs),
101        }
102    }
103
104    /// Subtracts two canonical values in this domain.
105    pub fn sub(self, lhs: Limbs, rhs: Limbs) -> Limbs {
106        match self {
107            Self::U256 => U256::sub(lhs, rhs),
108            Self::K1Base => K1Base::sub(lhs, rhs),
109            Self::K1Scalar => K1Scalar::sub(lhs, rhs),
110        }
111    }
112
113    /// Multiplies two canonical values in this domain.
114    pub fn mul(self, lhs: Limbs, rhs: Limbs) -> Limbs {
115        match self {
116            Self::U256 => U256::mul(lhs, rhs),
117            Self::K1Base => K1Base::mul(lhs, rhs),
118            Self::K1Scalar => K1Scalar::mul(lhs, rhs),
119        }
120    }
121
122    /// Returns the multiplicative inverse of `value` for declared prime-field domains.
123    pub fn inv(self, value: Limbs) -> Option<Limbs> {
124        match self {
125            Self::U256 => U256::inv(value),
126            Self::K1Base => K1Base::inv(value),
127            Self::K1Scalar => K1Scalar::inv(value),
128        }
129    }
130
131    /// Returns the maximum canonical value for U256.
132    pub fn max(self) -> Option<Limbs> {
133        match self {
134            Self::U256 => Some(U256::MAX),
135            _ => None,
136        }
137    }
138
139    /// Returns the canonical value `modulus - 1`, or `2^256 - 1` for U256.
140    pub fn minus_one(self) -> Limbs {
141        match self {
142            Self::U256 => U256::minus_one(),
143            Self::K1Base => K1Base::minus_one(),
144            Self::K1Scalar => K1Scalar::minus_one(),
145        }
146    }
147
148    /// Returns the field constant `1 / 2`, if this is a declared prime-field domain.
149    pub fn half(self) -> Option<Limbs> {
150        match self {
151            Self::U256 => U256::half(),
152            Self::K1Base => K1Base::half(),
153            Self::K1Scalar => K1Scalar::half(),
154        }
155    }
156
157    /// Returns `2^exponent` reduced into this prime-field domain.
158    pub fn pow2_mod(self, exponent: usize) -> Option<Limbs> {
159        match self {
160            Self::U256 => U256::pow2_mod(exponent),
161            Self::K1Base => K1Base::pow2_mod(exponent),
162            Self::K1Scalar => K1Scalar::pow2_mod(exponent),
163        }
164    }
165
166    /// Returns the generated field constants for prime-field domains.
167    pub fn field_constants(self) -> Option<[Limbs; 5]> {
168        if self.is_prime_field() {
169            Some([
170                self.minus_one(),
171                self.half()?,
172                self.pow2_mod(128)?,
173                self.pow2_mod(256)?,
174                self.pow2_mod(384)?,
175            ])
176        } else {
177            None
178        }
179    }
180}